Java中String的==比較,生成對象個數

“==”作用於字符串是比較地址是否相同!!比較字符串的值是否相同需要使用equals()方法。

1 常量池和堆上的字符串

String str1 = "abcd";
String str2 = "abcd";
String str3 = new String("abcd");
String str4 = new String("abcd");
String str5 = new StringBuilder("ab").append("cd").toString();
System.out.println(str1 == str2);  // true
System.out.println(str1 == str3);  // false
System.out.println(str1 == str4);  // false
System.out.println(str3 == str5);  // false

str1==str2 :true,這是因爲String str1 = “abcd”這種方式是生成了一個指向常量池中“abcd”對象的引用,若常量池中沒有“abcd”,則會新建一個,字符串str1和str2都是指向常量池中“abcd”對象的引用,這個過程只在常量池中新建了一個對象,因此相等。而str3,str4是在堆內存中各自新建了一個String對象,因此輸出false。至於會不會在常量池中創建對象,要看常量池中存不存在“abcd”,示例中是存在的,如不存在,則會在常量池中創建一個“abcd”對象,堆中的String對象的成員value會指向常量池中的對象。畫個圖:

value
value
str1
常量池-abcd對象
str2
str3
堆-abcd對象1
str4
堆-abcd對象2

至於str5是調用StringBuilder的toString方法返回new String(value, 0, count)實現的,同樣輸出false,但是要注意的是,str5的value不指向常量池的“abcd”對象,這是指向StringBuilder的成員變量value,同樣若常量池不存在“abcd”對象,也不會去常量區創建。

2 字符串拼接

String str1 = "abcd";
String str2 = "a" + "b" + "c" + "d";
String str3 = "ab" + "cd";
String tmp1 = "ab";
String tmp2 = "cd";
final String tmp3 = "ab";
String str4 = tmp1 + tmp2;
String str5 = tmp1 + "cd";
String str6 = tmp3 + "cd";
String str7 = tmp1 + tmp2;
System.out.println(str1 == str2);  // true-(1)
System.out.println(str1 == str3);  // true-(2)
System.out.println(str1 == str4);  // false-(3)
System.out.println(str1 == str5);  // false-(4)
System.out.println(str1 == str6);  // true-(5)
System.out.println(str4 == str7);  // false-(6)

str2和str3這種字符串連接在虛擬機進行編譯時會進行優化,直接將其編譯成這些常量相連的結果,指向常量池中的對象,而不是在運行時進行“+”計算,因此(1)(2)爲true。
str4、str5、str7這種有變量的連接方式,實際上是通過StringBuilder完成的,以str4爲例:

StringBuilder strB = new StringBuilder();
strB.append(tmp1);
StrB.append(tmp2);
// 如果有更多的連接,繼續append
String str4 = strB.toString();

這個過程產生一個StringBuilder對象,StringBuilder繼承了AbstractStringBuilder,AbstractStringBuilder中有成員char[] value,最後調用了StringBuilder的toString方法,其返回一個String對象,所以其過程產生3個對象,但是隻有一個String對象。str4、str5、str7各自指向堆中不同的String對象,雖然值相同,但是地址不同,所以(3)(4)(6)爲false。

// StringBuilder的構造函數
public StringBuilder(int capacity) {
    super(capacity);
}

// 其調用父類的構造函數
AbstractStringBuilder(int capacity) {
   value = new char[capacity];
}

// StringBuilder的toString方法
@Override
public String toString() {
    return new String(value, 0, count);
}

但是爲什麼同樣是有變量的連接方式,爲什麼str1 == str6輸出true,這裏是因爲final變量和普通變量的區別,當final修飾基本數據類型或String變量時,如果編輯期間能夠知道它的確切值,編譯器會把它當作常量使用,也就是說,用到該final變量的時候,相當於直接訪問這個常量,不需要在運行時確定,所以str6和str2、str3一樣,在編譯時就完成了連接,(5)爲true。如果在編譯時無法獲取到確切值,同樣會通過StringBuilder進行連接,則輸出false。

final String tmp3 ;
tmp3 = "cd";
String str6 = tmp3 + "cd";
System.out.println(str1 == str6);  // false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章