String str2 = new String("ABC");
上面語句創建了幾個字符串對象?上面語句實際上創建了2個字符串對象,一個是“ABC”這個直接量對應的對象,一個是new String()構造器返回的字符串對象。
在JVM里,考慮到垃圾回收(Garbage Collection)的方便,將heap(堆)划分為三部分:young generation(新生代)、tenured generation (old generation)(舊生代)、permanent generation(永生代)。
字符串為了解決字符串重復問題,生命周期長,存於pergmen中。
String str1 = “ABC”;可能創建一個或者不創建對象,如果”ABC”這個字符串在java String池里不存在,會在JVM的字符串池里創建一個創建一個String對象(“ABC”),然后str1指向這個內存地址,無論以后用這種方式創建多少個值為”ABC”的字符串對象,始終只有一個內存地址被分配,之后的都是String的拷貝,Java中稱為“字符串駐留”,所有的字符串常量都會在編譯之后自動地駐留。
String str2 = new String(“ABC”);至少創建一個對象,也可能兩個。因為用到new關鍵字,肯定會在heap中創建一個str2的String對象,它的value是“ABC”。同時如果這個字符串再java String池里不存在,會在java池里創建這個String對象“ABC”。
public class Test2 { public static void main(String[] args) { String s1 = new String("ABC"); String s2 = new String("ABC"); System.out.println(s1 == s2);//false System.out.println(s1.equals(s2));//true } }
如果將一個字符串連接表達式賦給字符串變量,如果這個字符串連接表達式的值可以在編譯時就確定下來,那么JVM會在編譯時確定字符串變量的值,並讓它指向字符串池中對應的字符串。
但是如果程序使用了變量或者調用了方法,那就只有在運行時才能確定該字符串表達式的值,因此無法在編譯時確定值,無法利用JVM的字符串池。
public class Test2 { public static void main(String[] args) { String s1 = "ABCDEF"; String s2 = "ABC" + "DEF"; System.out.println(s1 == s2);//true,可以在編譯時確定 String s3 = "DEF"; String s4 = "ABC" + s3; System.out.println(s1 == s4);//false,無法在編譯時確定 final String S5 = "DEF"; String s6 = "ABC" + S5; System.out.println(s1 == s6);//true,使用final關鍵字,在編譯時將對S5進行宏替換 } }
當程序中需要使用字符串、基本數據類型包裝實例時,應該盡量使用字符串直接量、基本數據類型的直接量,避免通過new String()、new Integer()等形式來創建字符串、基本數據類型包裝類實例,這樣能保證較好的性能。