大家先來看看一段奇怪的程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
這個程序真是簡單啊!可是有什麼問題呢?
1. 來自 String 的憂慮
上面這段程序中,到底有幾個對象呢?
可能很多人脫口而出:兩個,s1 和 s2
爲什麼?
String 是 final 類,它的值不可變。
看起來似乎很有道理,那麼來檢測一下吧,稍微改動一下程序
就可以看到結果了:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都會說已經不止兩個對象了
編譯並運行程序,輸出:s1 == s2
啊!
爲什麼 s1 == s2 ?
== 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"!
2. 千變萬化的 String
再稍微改動一下程序,會有更奇怪的發現:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
我們將 s2 用 new 操作符創建
程序輸出:
s1 != s2
s1 equals s2
嗯,很明顯嘛
s1 s2分別引用了兩個"Monday"String對象
可是爲什麼兩段程序不一樣呢?
3. 在 String 的游泳池中游泳
哈哈,翻了翻書終於找到了答案:
原來,程序在運行的時候會創建一個字符串緩衝池
當使用 s2 = "Monday" 這樣的表達是創建字符串的時候,程序首先會
在這個String緩衝池中尋找相同值的對象,在第一個程序中,s1先被
放到了池中,所以在s2被創建的時候,程序找到了具有相同值的 s1
將 s2 引用 s1 所引用的對象"Monday"
第二段程序中,使用了 new 操作符,他明白的告訴程序:
“我要一個新的!不要舊的!”與是一個新的"Monday"Sting對象被創
建在內存中。他們的值相同,但是位置不同,一個在池中游泳
一個在岸邊休息。哎呀,真是資源浪費,明明是一樣的非要分開做什麼呢?
4. 繼續潛水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
這次加入:s2 = s2.intern();
哇!程序輸出:
s1 == s2
s1 equals s2
原來,程序新建了 s2 之後,又用intern()把他打翻在了池裏
哈哈,這次 s2 和 s1 有引用了同樣的對象了
我們成功的減少了內存的佔用
5. == 與 equals() 的爭鬥
String 是個對象,要對比兩個不同的String對象的值是否相同
明顯的要用到 equals() 這個方法
可是如果程序裏面有那麼多的String對象,有那麼多次的要用到 equals ,
哦,天哪,真慢啊
更好的辦法:
把所有的String都intern()到緩衝池去吧
最好在用到new的時候就進行這個操作
String s2 = new String("Monday").intern();
這樣大家都在水池裏泡着了 。