1.10 “==”不等于“.equals”
這里舉出一個Java編程程序員經常碰到的問題。例如現在是凌晨3點,在你喝完第4杯咖啡后,你設法找到正確的邏輯來解決復雜的編程問題。到目前,你幾乎不能思考String和Object引用,因為你已經昏昏欲睡了。然后糟糕的事情發生了……不,并不是Java溢出,而是如下所示。
String name = getName();
if (name == "Sleepy") // oops!
{
doSomething();
}
|
你快速編譯并測試代碼后,代碼似乎正常運行。終于到下班回家休息的時候了!然而,一段時間后,應用程序測試發現了一個間歇性錯誤,并跟蹤到此錯誤的來源恰好是這段代碼。
“怎么會這樣?”你可能會憤怒地說,“前幾天我還試驗過類似的String比較,并且能夠正確運行!”。但是,你需要首先重溫一下Java對象引用的概念。一個對象變量是一個指向存儲在堆內存(heap memory)中實際對象的引用(指針)。當為另一個變量分配一個變量時,事實上分配的是引用而不是實際的對象(如圖1-1所示):
String a, b, c, d;
a = "123";
b = a;
c = new String("123");
d = "WCJ";
|
 |
圖 1-1 對象引用 |
Java中,“==”運算符用來比較兩個引用以查看它們是否指向同一個內存對象。而對于String實例,運行時狀態會盡可能地確保任意兩個具有相同字符信息的String字面值指向同一個內部對象。此過程稱為駐留(interning),但是它并不有助于每個String的比較。一個原因是垃圾收集器線程刪除了駐留值,另一個原因是String所在的位置可能被一個由String構造函數創建的新實例占用。如果是這樣,“==”將總是返回false。
可以設計equals方法來比較兩個對象的狀態(state)或每個對象的內容。對你自己的類,必須重寫此方法來使它正確操作。但是如果使用equals方法,String實例總是能夠正確地比較。假定所有的String值是駐留的,下面的代碼段說明了此問題:
String name1, name2, name3;
name1 = "123";
name2 = name1;
if (name1 == name2) {} // true
if (name1.equals(name2)) {} // true
name2 = "123";
if (name1 == name2) {} // usually true
if (name1.equals(name2)) {} // true
name3 = new String("123");
if (name1 == name3) {} // false
if (name1.equals(name3)) {} // true
|
注意:
總是使用.equals來比較兩個String值,盡管使用“==”運算符看似能夠正確操作。對于大多數應用程序而言,即使它能正確運行,但“==”代碼事實上是錯誤的,而只有equals是正確的。因此告訴所有你的開發同行支持String的“equals(平等)”權吧(這很可能是本書中最差的雙關語)!