一、String類的常見問題解析
1.1、new String(“hello”)創建了幾個對象
不考慮其他因素,String b = new String("hello");
這行代碼到底創建了幾個對象?
情況一,創建了一個
對象:
String a = "hello";
// 下面這一行代碼創建了一個對象
String b = new String("hello");
情況二,創建了兩個
對象:
// 下面這一行代碼創建了兩個對象
String b = new String("hello");
String a = "hello";
所以,在以下代碼片段
中,綜合其他代碼的情況下
,它可能是創建了一個,或者兩個對象。如果不考慮其他代碼
,就這樣一行運行,那麼它就是和第二種情況
一樣,創建了兩個對象
。
String b = new String("hello");
因爲在new String對象的時候,如果它需要的字符串在常量池中有了,那麼這個String對象的成員變量value[]
的值,就指向常量池中的對象,如果沒有,就在常量池中新建一個字符串對象,然後再指向它,而String對象本身是在堆裏的,下面進行詳細的解釋。
(1)創建了一個對象的情況(情況一)
"hello"
這個字符串,在創建對象之前,就在常量池
中已經存在了
:
(1)那麼第一行代碼String a = "hello";
就是在常量池中創建了值爲"hello"
的對象,我們討論的是第二行代碼。
(1)在第二行代碼String b = new String("hello");
是在堆
裏面創建了一個對象,引用b
指向這個對象,而常量池中有值爲"hello"
這個對象,然後引用b
指向的對象(new String("hello")
)的成員變量char
數組value[]
指向常量池值爲"hello"
這個對象就行了,它就創建了一個對象new String("hello")
。
下面進行驗證,我們將下面輸出語句打上斷點,方便進行查看:
在Debug模式下,可以看見變量a
和b
的成員變量char
數組value[]
的地址是一樣的,即是同一個char
數組,代碼String b = new String("hello");
並沒有爲它的成員變量value[]
創建新對象,而是指向了常量池中的值爲hello
的對象,即它只創建了一個對象。因此我們上面的分析是正確的。
(2)創建了兩個對象的情況(情況二)
"hello"
這個字符串,創建對象之前,在常量池
中不存在
:
(1)第一行代碼String b = new String("hello");
是在堆
裏面創建了一個對象,引用b
指向這個對象,然後發現常量池沒有值爲hello
的對象,於是進行創建,然後將這個String
對象成員變量char
數組value[]
,指向值爲"hello"
這個對象,這裏一行代碼就創建了兩個對象。
(2)然後第二行代碼String a = "hello";
直接將引用指向常量池中,值爲"hello"
的對象就行了。
下面進行驗證,同樣爲了方便進行查看,我們打上斷點,注意代碼順序調換了:
還是可以發現,變量a
和b
的成員變量char
數組value[]
的地址是一樣的,即是同一個char
數組,在執行String b = new String("hello");
有爲它的成員變量value[]
在常量池中創建新的對象,因爲代碼String a = "hello";
的對象是在常量池中,但它卻沒有指向新的對象,它的成員變量,和第一行代碼執行創建的對象的成員變量value[]
的地址是一樣的,即第一行代碼執行的時候創建了兩個對象。因此我們上面的分析是正確的。
注意:以上分析的時候,要知道String a = "hello";
創建的對象是在常量池中,String b = new String("hello");
創建的對象是在堆中。
1.2、判斷各種字符串對象相等的情況
如下代碼:
String s = "12";
String s1 = "34";
String s2 = s + s1;
String s3 = "1234";
String s4 = "12" + "34";
String s5 = s + "34";
String s6 = "12" + new String("34");
// 第一題
System.out.println(s2 == s3); // false
// 第二題
System.out.println(s2 == s4); // false
// 第三題
System.out.println(s3 == s4); // true
// 第四題
System.out.println(s3 == s5); // false
// 第五題
System.out.println(s2 == s5); // false
// 第六題
System.out.println(s3 == s6); // false
以上題目你是否做對了呢?
做題之前,我們先了解一下規則:
(1)、Sun規定String類型運算的時new了StringBuilder對象,然後用append()方法追加字符串,最終以StringBuilder的toString()方法返回,而它的toString()方法是直接new了一個String對象返回的,那麼 == 去比較兩個String對象的地址,肯定是不相等的。
(2)、像"a"+"a"
這種沒有變量參與則在編譯時就能確定,這種拼接會被優化,編譯器直接幫你拼好,就不需要new的操作。
於是就上面這些題目很容易得出結果了,注意第一題和第六題,因爲也有變量參與了運算,這種在編譯期也是無法確定的,也會根據規則(1)運算。