天天看點

String和new String的差別及StringBuilder拼接字元串

String和new String的差別

String s=“abc”;

String s1=“abc”;

String s2=new String(“abc”);

String s3=new String(“ABC”);

上述代碼中,

String s=“abc”;會在String常量池中建立一個字元串"abc",引用s指向常量池中的"abc"。隻建立一個對象。

String s1=“abc”;會首先在常量池中查找是否有"abc"這個對象,上一步中已經建立是以有,會直接将這個對象的位址賦給s1;

String s2=new String(“abc”);會首先在常量池中查找是否有"abc"這個對象,已經建立是以有,然後在堆中建立一個字元串"abc",并将其引用賦給是s2。也隻建立一個對象。

String s3=new String(“ABC”);會首先在常量池中查找是否有"ABC"這個對象,如果沒有,會首先在String常量池中建立一個字元串"ABC",然後在堆中建立一個字元串"ABC",并将其引用賦給是s3。建立兩個對象。

是以s和s1都指向String常量池中同一個對象。而s1和s2指向在堆中不同的兩個對象,雖然他們值相同,但位址不同。

String s=“a”;

String s1=s+“b”;

編譯期間會檢測到兩個字元串對象"a"和"b",在加載時直接在常量池建立兩個字元串對象"a"和"b",而String s1=s+“b”;編譯器不知道s1為多少,在運作時對象才會被建立,

而運作String s2=“a”+“b”;這段代碼時,編譯器可以直接算出s2為"ab",是以在加載時,常量池中隻會有字元串"ab",而"a"和"b"不會建立。

通過javap.exe 反編譯也可以驗證。

String和new String的差別及StringBuilder拼接字元串
String和new String的差別及StringBuilder拼接字元串

采用String進行字元串拼接的時候,可能會導緻記憶體洩漏。如下代碼所示。

String和new String的差別及StringBuilder拼接字元串

jvm虛拟機在運作這段代碼時,會在常量池中建立一個字元串"0",而進行字元串拼接時,會首先在堆中new 一個StringBuilder對象,然後通過它的append方法追加拼接的字元串,生成新的字元串。然後通過toString方法new 一個String類将新字元串指派給它。是以其實這一步會生成兩個對象。每一次循環都會産生很多個無用的String對象以及StringBuilder對象。

而将變量str聲明為StringBuilder類型時,其實底層的容器是數組結構,而且預設生成的長度為16,是以前15次循環不會建立新對象(初始化指派占了一個長度),當第16次循環時,長度不夠了,str會調用StringBuilder類的數組擴容方法,通過長度2+2建立一個數組容器(新的數組長度為34)并将之前數值複制進去然後通過append方法添加新的字元串。是以第16次執行完也會産生一個無用的StringBuilder對象,當容器又滿時,在建立一個長度為342+2=80的容器,之後過程類似。

為什麼StringBuilder效率高呢?

因為采用String每一次循環都會生成新的對象,結束後隻有最有一次指派才是有用的對象,是以會占系統資源,并且每次都建立對象也更耗時間,而垃圾回收機制是自動啟動的,無法控制,可能循環結束,都沒有啟動,就算啟動也會好系統資源與時間去處理大量無用的對象。而StringBuilder建立的對象很少,是以效率更高,占記憶體也小,GC回收的垃圾對象也很少。

是以在開發時盡量使用StringBuilder進行字元串拼接。