Java基礎之010-深入了解Java的String類
老帥
1. 首先String不屬于8種基本資料類型,String是一個類。
因為對象的預設值是null,是以String的預設值也是null;但它又是一種特殊的對象,有其它對象沒有的一些特性。
2. new String()和new String(“”)都是申明一個新的空字元串,是空串不是null;
3. String對象執行個體化
String str=”kvill”;
String str=new String (“kvill”);的差別:
在這裡,我們引入常量池這個簡單的概念。 常量池(constant pool)指的是在編譯期被确定,并被儲存在已編譯的.class檔案中的一些資料。它包括了關于類、方法、接口等中的常量,也包括字元串常量。
看例1:
String s0=”kvill”;
String s1=”kvill”;
String s2=”kv” + “ill”;
System.out.println( s0==s1 );
System.out.println( s0==s2 );
結果為:
true
true
首先,我們要知道Java會確定一個字元串常量隻有一個拷貝。
因為例子中的s0和s1中的”kvill”都是字元串常量,它們在編譯期就被确定了,是以s0==s1為true;而”kv”和”ill”也都是字元串常量,當一個字元串由多個字元串常量連接配接而成時,它自己肯定也是字元串常量,是以s2也同樣在編譯期就被解析為一個字元串常量,是以s2也是常量池中”kvill”的一個引用。
是以我們得出s0==s1==s2;
用new String() 建立的字元串不是常量,不能在編譯期就确定,是以new String() 建立的字元串不放入常量池中,它們有自己的位址空間。
看例2:
String s1=new String(”kvill”);
String s2=”kv” + new String(“ill”);
System.out.println( s0==s2 );
System.out.println( s1==s2 );
false
false
例2中s0還是常量池中”kvill”的應用,s1因為無法在編譯期确定,是以是運作時建立的新對象”kvill”的引用,s2因為有後半部分new String(“ill”)是以也無法在編譯期确定,是以也是一個新建立對象”kvill”的應用;明白了這些也就知道為何得出此結果了。
4. String.intern():
再補充介紹一點:存在于.class檔案中的常量池,在運作期被JVM裝載,并且可以擴充。String的intern()方法就是擴充常量池的一個方法;當一個String執行個體str調用intern()方法時,Java查找常量池中是否有相同Unicode的字元串常量,如果有,則傳回其的引用,如果沒有,則在常量池中增加一個Unicode等于str的字元串并傳回它的引用;看例3就清楚了
例3:
String s0= “kvill”;
String s2=new String(“kvill”);
System.out.println( “**********” );
s1.intern();
s2=s2.intern(); //把常量池中“kvill”的引用賦給s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
**********
false //雖然執行了s1.intern(),但它的傳回值沒有賦給s1
true //說明s1.intern()傳回的是常量池中”kvill”的引用
5. 關于equals()和==:
這個equals()對于String簡單來說就是比較兩字元串的Unicode序列是否相當,如果相等傳回true;
而==是比較兩字元串的位址是否相同,也就是是否是同一個字元串的引用。
6. String和StringBuffer的差別
某些特别情況下, String 對象的字元串拼接其實是被 JVM 解釋成了 StringBuffer 對象的拼接,是以這些時候 String 對象的速度并不會比 StringBuffer 對象慢,如在以下的字元串對象生成中, String 效率是遠要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你會很驚訝的發現,生成 String S1 對象的速度簡直太快了,而這個時候 StringBuffer 居然速度上根本一點都不占優勢。其實這是 JVM 的一個把戲,在 JVM 眼裡,這個 String S1 = “This is only a” + “ simple” + “test”; 其實就是: String S1 = “This is only a simple test”; 是以當然不需要太多的時間了。
但大家這裡要注意的是,如果你的字元串是來自另外的 String 對象的話,速度就沒那麼快了,譬如: String S2 = “This is only a”; String S3 = “ simple”; String S4 = “ test”; String S1 = S2 +S3 + S4; 這時候 JVM 會規規矩矩的按照原來的方式去做。
7. 建立了幾個對象
7.1 這個方法建立了幾個對象
String s = new String( "xyz ");
這個語句建立了幾個對象? 可能是一個,因為常量池中可能已經存在“xyz”這個對象了(編譯器建立),是以這個語句不會再在常量池中建立了,隻在堆裡建立一個對象(運作期建立)。如果常量池中不存在“xyz”,則會建立兩個。
7.2 String s = "a" + "b";建立了幾個對象
下面簡單證明我的推斷,首先編譯這個類:
複制class檔案備用,然後修改為
再次編譯,用ue之類的文本編輯器打開,察看二進制内容,可以發現,兩個class檔案完全一緻,連一個位元組都不差.
ok,真相大白了.根本不存在運作期的處理String b = "a" + "b";這樣的代碼的問題,編譯時就直接優化掉了。
也就是說常量池中不會生成三個常量:b1="a", b2="b", b="ab",隻會生成 一個b="ab"
8、String是不可變的
String使用private final char value[]來實作字元串的存儲,也就是說String對象建立之後,就不能再修改此對象中存儲的字元串内容,就是因為如此,才說String類型是不可變的(immutable).