1. 程式人生 > >字串比較問題的內部分析

字串比較問題的內部分析

字串比較

Step1

我在CDSN論壇上看到這樣一個帖子,覺得挺不錯的,自己在這方面也正在學,於是乎去嘗試了一下,問題截圖如下:
原帖連結:http://bbs.csdn.net/topics/391957440
123313

下面是那位貼出問題的博友,在得到網友回答後寫出的總結:
1: 對於 String str3 = “JavaEE” + “Android”;這條語句會在編譯時期確定,如果常量池中有 “JavaEEAndroid”則會將這個字串的地址放到str3中。
如果沒有,則會在常量池中新建,然後賦值引用。
2: 對於 str1= str1 + “Android”; 在編譯時並沒有確定,只有在執行時才能確定值。所以會在堆中新建物件String 型別 然後賦值給str1;
這樣str1 所引用的地址並不是”JavaEEAndroid”的地址。所以不相等。

Step2

我拿到這個問題後,也學著我之前看視訊的老師那樣,畫畫內部原理圖,如下:

額箝位器

等我畫完才發現,從我這樣畫的原理圖,最終str1與str3應該是一樣的地址引用值才對,可結果 str1 == str3 為 false,就說明這裡str1與str3實際上是不等的。

於是又折騰了一晚上,等到第二天才算是將其弄清楚,見下圖。

Step3

以下是我的見解:
下面是一個Java字串連線的例子:

String one = "Hello";
String two = "World";
String three = one + " " + two;

編譯器最終會把上面的程式碼編譯為類似下面的程式碼:

String one = "Hello";
String two = " World";

String three = new StringBuilder(one).append(two).toString();

此程式碼實際上建立了兩個物件:一個StringBuilder例項,然後從toString()方法返回一個新的String例項。

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

此處最終得到的是new 出來的一個String例項,進而會在堆中開闢一個空間,繼而String 的引用result 會指向這個新開闢的起始地址

仍需注意的是,上例中StringBuilder()和append()傳進去的引數是String型別的,當定義的String型別被如下final修飾的時候,str1直接就是常量了:

@Test
public void Test01(){
    final String str1 = "JavaEE";
    String str = str1 + "Android";
    String str3 = "JavaEEAndroid";
    System.out.println(str3 == str);//true
    System.out.println(str3.equals(str));//true
}

3213we

此處str3 與 str1就不會像第一例那樣呼叫StringBuilder進行字串的串聯,而是直接相連線存入到常量池中

Step4

總結:這裡理解的重點是,在字串用’+‘號串聯時,什麼時候用” new StringBuilder(one).append(two).toString();”的形式,什麼時候直接相連,
關鍵看’+‘號兩側的字串是變數還是常量,若都為String型別的引用變數,則必定是呼叫StringBuilder方法,若存在宣告為final的常量,則直接相連,
補充一點:前者是在堆中重新開闢一個儲存空間,用來儲存指向常量池中該字串的首地址;而後者是直接在堆常量池中建立串聯後的新字串(若池中
原先就存在了,就直接用原來的)