天天看點

Java基礎之010-深入了解Java的String類

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).