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