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模式下,可以看見變量ab的成員變量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"的對象就行了。

  下面進行驗證,同樣爲了方便進行查看,我們打上斷點,注意代碼順序調換了:
這裏寫圖片描述

  還是可以發現,變量ab的成員變量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)運算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章