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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...