目錄
1. 字元串
1. 字元串建立
2. 執行個體化的差別
I. 直接指派
II. 構造方法
3. 字元串比較
4. 字元串的修改
5. String類總結
【String類方法 】String 類是Java類中最常用用的類,記錄一下 String類的對象執行個體以及String常用的一些方法
1. 字元串
【字元串的特點】
- 字元串内容永不可變
- 字元串可以共享使用【在常量池中】
- 字元串,字元數組,底層原理是byte[ ]位元組數組
1. 字元串建立
直接指派
這種指派方式最為常用。
但是String本身畢竟是一個類,既然是類,那麼類中一定存在構造方法。String類也不例外,String類的其中一種構造方法如下:
public String(String str);
構造方法建立
1. public String( ) :預設構造方法建立字元串
String msg = new String();
2. 根據字元數組建立字元串
3. 根據位元組數組建立字元串(字元串底層其實還是位元組存儲)
2. 執行個體化的差別
I. 直接指派
- 對于基本類型來說:== 是數值的比較
- 對于引用類型來說:== 是位址值的比較
記憶體圖詳解:
為什麼現在并沒有開辟新的堆記憶體空間呢?
直接指派會把建立的字元串放到字元串常量池中,隻有通過構造方法new出來的,每次才會開辟新空間。
常量優化機制:
String類的設計使用了共享設計模式
在JVM底層實際上會自動維護一個對象池(字元串對象池),如果現在采用了直接指派的模式進行String類的對象執行個體化操作,那麼該執行個體化對象(字元串内容)将自動儲存到這個對象池之中。
- 如果下次繼續使用直接指派的模式聲明String類對象,此時對象池之中如若有指定内容,将直接進行引用;
- 如若沒有,則開辟新的字元串對象而後将其儲存在對象池之中,以供下次使用(目的就是減少開銷)
- 所謂的對象池就是一個對象數組
II. 構造方法
類對象使用構造方法執行個體化是标準做法
String str = new String("hello");
通過分析可知,如果使用String構造方法就會開辟兩塊堆記憶體空間,并且其中一塊堆記憶體将成為垃圾空間。除了這
一缺點之外,也會對字元串共享産生問題。
面試題:請解釋String類中兩種對象執行個體化的差別
- 直接指派:隻會開辟一塊堆記憶體空間,并且該字元串對象可以自動儲存在對象池中以供下次使用。
- 構造方法:會開辟兩塊堆記憶體空間,其中一塊成為垃圾空間,不會自動儲存在對象池中,可以使用intern()方法手工入池。
是以,一般會采取第一種方式即直接指派即可......
3. 字元串比較
- ==
- equals()
== 本身是進行數值比較的,如果現在用于對象比較,那麼所比較的就應該是兩個對象所儲存的位址值比較,而并沒有比較對象的内容
那麼要想比較内容比較,則必須采用String類提供的equals方法。
使用equals方法比較字元串内容:
Object類equals方法的覆寫
用equals( )來比較對象内容是否相同:
兩個對象stu1 和 stu2 的内容明明相等,應該是true呀?怎麼會是false?
因為此時直接調用
equals()
方法預設進行比較的是兩個對象的位址。new一下就會在堆上建立新空間,位址自然不會相同,是以為false
我們在判斷的是字元串的内容是否相等時,直接用 str1.equals(str2);
但是在判斷兩個對象是否相等時,比如要判斷一個Person類的兩個對象的姓名是否相同時,此時要重新覆寫equals( )
面試題:請解釋String類 == 與equals 的差別
- " == ":引用類型進行的數值比較,比較的是兩個字元串對象的記憶體位址數值
- "equals( )":可以進行字元串内容的比較
在Java中,本身也沒有直接提供字元串常量的概念,所有使用 " " 定義的内容本質上來講都是String的匿名對象
觀察字元串常量:
那麼在之前出現的String str = "Hello",本質上就是将一個匿名的String類對象設定有名字,而且匿名對象一定儲存在堆記憶體中。
PS :
String str = null ; // 假設由使用者輸入
System.out.println(str.equals("Hello"));
在進行接收使用者輸入資料的時候一定要考慮到使用者沒有輸入的問題,使用者沒有輸入的時候,一定會出現 NullPointerException 問題
是以應當改為:
常量的字元串内容放在前面,來避免空指針異常:
System.out.println("Hello".equals(str));
4. 字元串的修改
String類是不可變類,String類的對象一旦被建立,其值将不能被改動
但實際情況是
此處str卻是被修改過了,這是為什麼呢?
可以發現字元串上沒有發生任何變化,但是字元串對象的引用一直在改變,而且會形成大量的垃圾空間
String字元串修改實作原理:
當用String類型來對字元串進行修改時,首先是建立一個StringBuilder,其次調用 StringBuilder 的 append( ) 方法,最後掉調用StringBulider 的 toString( )将結果傳回
示例如下:
等價于
str字元串的内容不可改變,改變的是引用的位址值
5. String類總結
面試題:
Q: String類能不能被繼承,有沒有子類?
String類被final修飾,其不能被繼承,是以沒有子類
Q1: s1 與 s2 是否相等?
- true
- true
Q2: s1 與 s2 是否相等?記憶體中共有幾個abc?
- false
- true
- 記憶體中有兩個abc,一個在堆區,一個在常量池中
Q3: s1 與 s2 是否相等?
- true
- true
這便是Java的常量優化機制。Java程式時半編譯半解釋性語言,先将 .java 檔案編譯成 .class 位元組碼檔案,最後再執行。差別于編譯型語言,直接将源代碼翻譯成二進制的機器碼。在編譯成 .class 檔案後,s1 與 s2 的内容是相同的,是以隻是引用改變了而已。
Q4: s1 與 s2 是否相等?
- false
- true
s1,s2是變量,而 s3 則是變量.