字串比較問題的內部分析
字串比較
Step1
我在CDSN論壇上看到這樣一個帖子,覺得挺不錯的,自己在這方面也正在學,於是乎去嘗試了一下,問題截圖如下:
原帖連結:http://bbs.csdn.net/topics/391957440
下面是那位貼出問題的博友,在得到網友回答後寫出的總結:
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
}
此處str3 與 str1就不會像第一例那樣呼叫StringBuilder進行字串的串聯,而是直接相連線存入到常量池中
Step4
總結:這裡理解的重點是,在字串用’+‘號串聯時,什麼時候用” new StringBuilder(one).append(two).toString();”的形式,什麼時候直接相連,
關鍵看’+‘號兩側的字串是變數還是常量,若都為String型別的引用變數,則必定是呼叫StringBuilder方法,若存在宣告為final的常量,則直接相連,
補充一點:前者是在堆中重新開闢一個儲存空間,用來儲存指向常量池中該字串的首地址;而後者是直接在堆常量池中建立串聯後的新字串(若池中
原先就存在了,就直接用原來的)