JavaSE學習筆記(5)---內部類和String類

来源:https://www.cnblogs.com/xjtu-lyh/archive/2020/02/07/12274867.html
-Advertisement-
Play Games

JavaSE學習筆記(5) 內部類和String類 一.內部類基礎 轉自 "菜鳥教程" ​ 在 Java 中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類。下麵就先來瞭解一下這四種內部類的用法 ...


JavaSE學習筆記(5)---內部類和String類

一.內部類基礎

轉自菜鳥教程

​ 在 Java 中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類。下麵就先來瞭解一下這四種內部類的用法。

1.成員內部類

​ 成員內部類是最普通的內部類,它的定義為位於另一個類的內部,形如下麵的形式:

class Circle {
    double radius = 0;
     
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //內部類
        public void drawSahpe() {
            System.out.println("drawshape");
        }
    }
}

​ 這樣看起來,類Draw像是類Circle的一個成員,Circle稱為外部類。成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員)。

class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //內部類
        public void drawSahpe() {
            System.out.println(radius);  //外部類的private成員
            System.out.println(count);   //外部類的靜態成員
        }
    }
}

​ 不過要註意的是,當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下麵的形式進行訪問:

外部類.this.成員變數
外部類.this.成員方法

​ 雖然成員內部類可以無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼隨心所欲了。在外部類中如果要訪問成員內部類的成員,必須先創建一個成員內部類的對象,再通過指向這個對象的引用來訪問:

class Circle {
    private double radius = 0;
 
    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必須先創建成員內部類的對象,再進行訪問
    }
     
    private Draw getDrawInstance() {
        return new Draw();
    }
     
    class Draw {     //內部類
        public void drawSahpe() {
            System.out.println(radius);  //外部類的private成員
        }
    }
}

​ 成員內部類是依附外部類而存在的,也就是說,如果要創建成員內部類的對象,前提是必須存在一個外部類的對象。創建成員內部類對象的一般方式如下:

public class Test {
    public static void main(String[] args)  {
        //第一種方式:
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必須通過Outter對象來創建
         
        //第二種方式:
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}
 
class Outter {
    private Inner inner = null;
    public Outter() {         
    }
     
    public Inner getInnerInstance() {
        if(inner == null)
            inner = new Inner();
        return inner;
    }
      
    class Inner {
        public Inner() {             
        }
    }
}

​ 內部類可以擁有 private 訪問許可權、protected 訪問許可權、public 訪問許可權及包訪問許可權。比如上面的例子,如果成員內部類 Inner 用 private 修飾,則只能在外部類的內部訪問,如果用 public 修飾,則任何地方都能訪問;如果用 protected 修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是預設訪問許可權,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被 public 和包訪問兩種許可權修飾。我個人是這麼理解的,由於成員內部類看起來像是外部類的一個成員,所以可以像類的成員一樣擁有多種許可權修飾。

2.局部內部類

​ 局部內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該作用域內。

class People{
    public People() {
         
    }
}
 
class Man{
    public Man(){
         
    }
     
    public People getWoman(){
        class Woman extends People{   //局部內部類
            int age =0;
        }
        return new Woman();
    }
}

 

註意: 局部內部類就像是方法裡面的一個局部變數一樣,是不能有 public、protected、private 以及 static 修飾符的。

3.匿名內部類

匿名內部類應該是平時我們編寫代碼時用得最多的,在編寫事件監聽的代碼時使用匿名內部類不但方便,而且使代碼更加容易維護。下麵這段代碼是一段 Android 事件監聽代碼:

scan_bt.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub         
    }
});
 
history_bt.setOnClickListener(new OnClickListener() {
     
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
         
    }
});

這段代碼為兩個按鈕設置監聽器,這裡面就使用了匿名內部類。這段代碼中的:

new OnClickListener() {
    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
         
    }
}

就是匿名內部類的使用。代碼中需要給按鈕設置監聽器對象,使用匿名內部類能夠在實現父類或者介面中的方法情況下同時產生一個相應的對象,但是前提是這個父類或者介面必須先存在才能這樣使用。當然像下麵這種寫法也是可以的,跟上面使用匿名內部類達到效果相同。

private void setListener()
{
    scan_bt.setOnClickListener(new Listener1());       
    history_bt.setOnClickListener(new Listener2());
}
 
class Listener1 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub             
    }
}
 
class Listener2 implements View.OnClickListener{
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub             
    }
}

​ 這種寫法雖然能達到一樣的效果,但是既冗長又難以維護,所以一般使用匿名內部類的方法來編寫事件監聽代碼。同樣的,匿名內部類也是不能有訪問修飾符和 static 修飾符的。

​ 匿名內部類是唯一一種沒有構造器的類。正因為其沒有構造器,所以匿名內部類的使用範圍非常有限,大部分匿名內部類用於介面回調。匿名內部類在編譯的時候由系統自動起名為 Outter$1.class。一般來說,匿名內部類用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。

4.靜態內部類

​ 靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變數或者方法,這點很好理解,因為在沒有外部類的對象的情況下,可以創建靜態內部類的對象,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的對象。

public class Test {
    public static void main(String[] args)  {
        Outter.Inner inner = new Outter.Inner();
    }
}
 
class Outter {
    public Outter() {      
    }
     
    static class Inner {
        public Inner() {    
        }
    }
}

String類

  1. String類又稱作不可變字元序列。

  2. String位於java.lang包中,Java程式預設導入java.lang包下的所有類。

  3. Java字元串就是Unicode字元序列,例如字元串“Java”就是4個Unicode字元’J’、’a’、’v’、’a’組成的。

  4. Java沒有內置的字元串類型,而是在標準Java類庫中提供了一個預定義的類String,每個用雙引號括起來的字元串都是String類的一個實例。
  5. Java允許使用符號"+"把兩個字元串連接起來。

String類的實例

String e = ""  ; // 空字元串
String greeting = " Hello World ";

字元串連接

String s1 = "Hello";
String s2 = "World! ";
String s = s1 + s2; //HelloWorld!

​ n-符號"+"把兩個字元串按給定的順序連接在一起,並且是完全按照給定的形式。

​ n-當"+"運算符兩側的操作數中只要有一個是字元串(String)類型,系統會自動將另一個操作數轉換為字元串然後再進行連接。

"+"連接符

int age = 18;
String str = "age is" + age;  //str賦值為"age is 18"
//這種特性通常被用在輸出語句中:
System.out.println("age  is" + age);

常量池

在Java的記憶體分析中,我們會經常聽到關於“常量池”的描述,實際上常量池也分了以下三種:

1. 全局字元串常量池(String Pool)

全局字元串常量池中存放的內容是在類載入完成後存到String Pool中的,在每個VM中只有一份,存放的是字元串常量的引用值(在堆中生成字元串對象實例)。

2. class文件常量池(Class Constant Pool)

class常量池是在編譯的時候每個class都有的,在編譯階段,存放的是常量(文本字元串、final常量等)和符號引用。

3. 運行時常量池(Runtime Constant Pool)

運行時常量池是在類載入完成之後,將每個class常量池中的符號引用值轉存到運行時常量池中,也就是說,每個class都有一個運行時常量池,類在解析之後,將符號引用替換成直接引用,與全局常量池中的引用值保持一致。

常量池示例

String str1 = "abc";
String str2 = new String("def");
String str3 = "abc";
String str4 = str2.intern();
String str5 = "def";
System.out.println(str1 == str3);// true
System.out.println(str2 == str4);// false
System.out.println(str4 == str5);// true

示例中首先經過編譯之後,在該類的class常量池中存放一些符號引用,然後類載入之後,將class常量池中存放的符號引用轉存到運行時常量池中,然後經過驗證,準備階段之後,在堆中生成駐留字元串的實例對象(也就是上例中str1所指向的“abc”實例對象),然後將這個對象的引用存到全局String Pool中,也就是String Pool中,最後在解析階段,要把運行時常量池中的符號引用替換成直接引用,那麼就直接查詢String Pool,保證String Pool里的引用值與運行時常量池中的引用值一致,大概整個過程就是這樣了。

回到示例的程式,現在就很容易解釋整個程式的記憶體分配過程了,首先,在堆中會有一個“abc”實例,全局String Pool中存放著“abc”的一個引用值,然後在運行第二句的時候會生成兩個實例,一個是“def”的實例對象,並且String Pool中存儲一個“def”的引用值,還有一個是new出來的一個“def”的實例對象,與上面那個是不同的實例,當在解析str3的時候查找String Pool,裡面有“abc”的全局駐留字元串引用,所以str3的引用地址與之前的那個已存在的相同,str4是在運行的時候調用intern()函數,返回String Pool中“def”的引用值,如果沒有就將str2的引用值添加進去,在這裡,String Pool中已經有了“def”的引用值了,所以返回上面在new str2的時候添加到String Pool中的 “def”引用值,最後str5在解析的時候就也是指向存在於String Pool中的“def”的引用值,那麼這樣一分析之後,結果就容易理解了。

String類常用方法

轉自尚學堂筆記

String類是我們最常使用的類。字元串類的方法我們必須非常熟悉!我們列出常用的方法,請大家熟悉。

String類的常用方法列表

圖2.png

String類常用方法一

public class StringTest1 {
    public static void main(String[] args) {
        String s1 = "core Java";
        String s2 = "Core Java";
        System.out.println(s1.charAt(3));//提取下標為3的字元
        System.out.println(s2.length());//字元串的長度
        System.out.println(s1.equals(s2));//比較兩個字元串是否相等
        System.out.println(s1.equalsIgnoreCase(s2));//比較兩個字元串(忽略大小寫)
        System.out.println(s1.indexOf("Java"));//字元串s1中是否包含Java
        System.out.println(s1.indexOf("apple"));//字元串s1中是否包含apple
        String s = s1.replace(' ', '&');//將s1中的空格替換成&
        System.out.println("result is :" + s);
    }
}

執行結果如圖所示:

圖5-31 示例5-29運行效果圖.png

String類常用方法二

public class StringTest2 {
    public static void main(String[] args) {
        String s = "";
        String s1 = "How are you?";
        System.out.println(s1.startsWith("How"));//是否以How開頭
        System.out.println(s1.endsWith("you"));//是否以you結尾
        s = s1.substring(4);//提取子字元串:從下標為4的開始到字元串結尾為止
        System.out.println(s);
        s = s1.substring(4, 7);//提取子字元串:下標[4, 7) 不包括7
        System.out.println(s);
        s = s1.toLowerCase();//轉小寫
        System.out.println(s);
        s = s1.toUpperCase();//轉大寫
        System.out.println(s);
        String s2 = "  How old are you!! ";
        s = s2.trim();//去除字元串首尾的空格。註意:中間的空格不能去除
        System.out.println(s);
        System.out.println(s2);//因為String是不可變字元串,所以s2不變
    }
}

執行結果如圖所示:

圖5-32 示例5-30運行效果圖.png

字元串相等的判斷

  1. equals方法用來檢測兩個字元串內容是否相等。如果字元串s和t內容相等,則s.equals(t)返回true,否則返回false。

  2. 要測試兩個字元串除了大小寫區別外是否是相等的,需要使用equalsIgnoreCase方法。

  3. 判斷字元串是否相等不要使用"=="。

忽略大小寫的字元串比較

"Hello".equalsIgnoreCase("hellO");//true

字元串的比較"=="與equals()方法

public class TestStringEquals {
    public static void main(String[] args) {
        String g1 = "北京尚學堂";
        String g2 = "北京尚學堂";
        String g3 = new String("北京尚學堂");
        System.out.println(g1 == g2); // true  指向同樣的字元串常量對象
        System.out.println(g1 == g3); // false  g3是新創建的對象
        System.out.println(g1.equals(g3)); // true  g1和g3裡面的字元串內容是一樣的
    }
}

執行結果如圖所示:

圖5-33 示例5-32運行效果圖.png

示例的記憶體分析如圖所示:

圖5-34 示例5-32記憶體分析圖.png


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • |這個作業屬於哪個課程|軟體工程| | | | |這個作業要求在哪裡|第一次個人編程作業| |這個作業的目標|完成漢字編程| |作業正文|見下文 | |其他參考文獻|無,但是感謝洪成龍與陳徳渠的解答 | 編程信息 時間:2020.02.06|2020.02.07 代碼行數:86行|338行 需求分析 ...
  • 前言:之前打 CTF 的時候都是零零碎碎的學習Python,沒有成體系,學得不精。趁著過年的這段時間好好地系統學習一下,加強自己的python技能。同時也做一個記錄,用來總結和反思,如果能給後學者一點幫助,那就再好不過了。 [TOC] 一、Python的下載 1. 到Python的 "官網" 上看適 ...
  • 1.CS和BS CS:Client/Server 客戶端和伺服器,這種軟體往往需要安裝。比如QQ、迅雷、播放器。 優點 : 可以減輕伺服器端壓力,將部分代碼寫到客戶端,並且界面很美觀。 缺點 : 一旦伺服器更新了,客戶端也需要更新,分散式開發比較弱。 BS:Browser/Server 瀏覽器和服務 ...
  • 今日內容 裝飾器 推導式 模塊【可選】 內容回顧 1. 函數 參數 def (a1,a2):pass def (a1,a2=None):pass 預設參數推薦用不可變類型,慎用可變類型。 def( args, kwargs):pass 註意:位置參數 關鍵字參數 面試題 函數可以做參數【知識點】。 ...
  • 本來想著直接說線程池的,不過在說線程池之前,我們必須要知道併發安全隊列;因為一般情況下線程池中的線程數量是一定的,肯定不會超過某個閾值,那麼當任務太多了的時候,我們必須把多餘的任務保存到併發安全隊列中,當線程池中的線程空閑下來了,就會到併發安全隊列中拿任務; 那麼什麼是併發安全隊列呢?其實可以簡單看 ...
  • Tensorflow機器學習入門——網路可視化TensorBoard ...
  • *Preparation 1. Black's Futures Option Model (1) Key parameter: S = F, b = 0; (2) Task: Need an option for an asset (futures price = 120), assume K = ...
  • 一、前言 近期疫情嚴重,身為社畜的我只能在家中繼續鑽研技術了。之前寫過一篇關於搭建FIFO驗證平臺的博文,利用SV的OOP特性對FIFO進行初步驗證,但有很多不足之處,比如結構不夠規範、驗證組件類不獨立於DUT等問題。此次嘗試驗證更複雜的IP,並利用SV的更多高級特性來搭建層次化驗證平臺。 二、AP ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...