String的兩種賦值是不同的,String str1=“hello”,指向堆內存中的"hello",而String str2=new String("hello"),因爲new開闢的新的堆內存,所以二者地址不同,在用==時,顯示的是false。
例一:
String str1=“Hello”;
String str2=“Hello”;
String str3=“Hello”;
這時候三者都是指向同一堆內存地址,因爲如果對象池中已經有了相同的字符串聲明時,就不會再重新開闢空間了。
可是,如果先用String str1=new String("hello"),開闢新的堆內存,內容爲"hello",
這時再寫String str2="hello"呢,第一句中new已經新開闢了,對象池中就存在了"hello",
這時第二句中應該指向已經存在的地址,也就是和第一句new開闢的時同一堆內存地址呀,
但是爲什麼用==時,顯示的還是false呢?
求解答
因爲每一個字符串都是一個String類的匿名對象,所以首先會在堆內存中開闢一塊空間保存字符串“Hello”,而後又使用了關鍵字 new 開闢的堆內存,而之前定義的字符串常量的堆內存空間將不會有任何的棧內存指向空間,就成爲垃圾,等待被GC回收。所以,使用構造方法開闢的字符串對象實際上會開闢兩塊空間,其中有一塊空間將成爲垃圾。另外,使用構造方法實例化的String 類對象內容不會保存在字符串對象池中,既不能夠進行共享數據操作。
觀察入池問題:
public class StringDemo(){
public static void main(String[] args){
String str1 = new String( "Hello" );
String str2 = "Hello";
String str3 = "Hello";
System.out.println( str1 == str2 );
System.out.println( str1 == str3 );
System.out.println( str2 == str3 );
}
}
程序運行結果:
false
false
true
通過上面的程序可以發現,使用構造方法實例化的String 對象不會入池,所以,通過構造方法實例化的String類對象只能自己使用。但在String類中爲了方便操作提供了一種稱爲手工入池的方法: public String intern();
實例:手工入池
public class StringDemo{
public static void main(String[] args){
String str1 = new String( "Hello" ).intern(); //入池
String str2 = "Hello"; //使用池對象
String str3 = "Hello"; //使用池對象
System.out.println(str1 == str2); //true
System.out.println(str1 == str3); //true
System.out.println(str2 == str3); //true
}
}
程序運行結果:
true
true
true
本程序在使用 String 類構造方法實例化對象後又調用了String 類的 intern() 方法,而這個方法就表示將開闢的字符串對象保存在對象池中,所以日後利用直接賦值方式完成的 String 類對象實例化,就可以直接從對象池中取出數據進行操作,而不再需要重新開闢新的對象了。
常見面試題分析: 請解釋String 類的兩種對象實例化方式的區別。
直接賦值:只開闢一塊堆內存空間,字符串的內容可以自動入池,以供下次使用;
構造方法:開闢兩塊堆內存空間,有一塊將成爲垃圾,並且不能自動入池,需要使用intern()手工入池。
常見面試題分析:代碼“String s = new String ("mldn");”創建了幾個String 類的實例化對象?
創建了兩個實例化對象,一個是String類的匿名對象“mldn”,另外一個是使用關鍵字new 實例化的String 類對象。