Java中String建立物件過程及其運算原理
一、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)運算。