1. 程式人生 > >Java中String建立物件過程及其運算原理

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)運算。