java字串常量池——字串==比較的一個誤區
阿新 • • 發佈:2018-12-06
轉自:https://blog.csdn.net/wxz980927155/article/details/81712342
起因
再一次js的json物件的比較中,發現相同內容的json物件使用==比較並不相等。
例如:
var obj = {};
var obj2 = {};
console.log(obj == obj2); // 結果為false
json在js中代表一個物件==比較的是物件棧中存放引用堆的地址。上面的obj和obj2建立的是兩個物件地址肯定不同結果為false。
但最令我不解的是為什麼js的字串比較可以用==來比較字串的內容是否相等,而java卻要使用equals去比較字串的內容是否相等。但當我發現下面程式碼的時候又重新整理了我這個菜鳥的認知。
String str1 = "test";
String str2 = "test";
System.out.println(str1 == str2); // 結果為true
結果難道不該為false嗎?字串的比較難道不是用equals來比較內容是否相等嗎?兩個不同的物件建立的記憶體地址應該是不一樣的啊!!後來經過網上查閱資料發現jvm還存在一個字串常量池。
字串常量池
讓我們先分析一下上述的程式碼:
在我的理解中常量池應該是為了減少開發者對字串過度的建立,導致記憶體使用率的提升,畢竟String類是一個final類,操作字串永遠不會改變當前字串的值,只會新增一個字串物件。
String str1 = "test";
/* jvm在編譯的時候會先檢視str1字面量test是否存放在字串常量池中有則直
接引用字串常量池裡面的地址,沒有則在字串常量池新建立一個*/
String str2 = "test"; /* str2發現字串常量池裡面已經有了test則直接把字串常量池裡面的地址拿 了過來*/ System.out.println(str1 == str2); // 最終str1和str2的地址都是相同的結果肯定為true啦
既然都到這裡在拓展拓展在走唄
String str1 = new String("test");
String str2 = new String("test"); System.out.println(str1 == str2); // 結果為false // 這個為什麼不為true了呢?
new String()會在程式碼執行的時候在堆中開闢一個空間存放引用字串常量池裡面的地址但是棧裡面引用的堆的地址是不一樣的,所以即使引用的字串常量池裡面的地址是一樣也永遠不可能為true!!
intern方法
強制String物件使用字串常量池
String str1 = new String("test");
String str2 = new String("test"); str1 = str1.intern(); str2 = str2.intern(); System.out.println(str1 == str2); // 結果為true
經典面試題
String str1 = new String("test");
// 此程式碼執行會建立幾個物件? // A:1個或2個,堆中會建立一個,字串常量池中有test則常量池中不會建立,沒有則建立
總結
-
字串字面量會在編譯的就開始判斷是否在字串常量池裡面建立,而new String()會在程式碼執行的時候才去判斷。
-
字串常量池裡面沒有此字串則會建立,有則會去引用字串常量池裡面的字串。字面量裡字串常量池的地址存放在棧中,new String()則存放在堆中。