第8條:覆蓋equals時請遵守通用約定
1. 前言
覆蓋equals方法看似很簡單邦尊,但是有許多覆蓋方法或?qū)е洛e誤穗酥,避免這些錯誤最直接的方法就是不覆蓋equals立由,這樣后裸,沒有對象就只與自己相等。
2. 不需要覆蓋equals方法的情況有哪些?
(1)類的每一個實體本質(zhì)上都是唯一的轿衔。比如Thread類沉迹,每一個實體都是唯一的,所以不需要覆蓋equals方法害驹。
(2)不關(guān)心類是否提供了“邏輯相等”的測試功能鞭呕。·
(3)父類已經(jīng)覆蓋了equals方法,并且在子類中這些方法同樣適用宛官。
(4)類是私有的或是包級私有的葫松,可以確定equals方法永遠(yuǎn)不會被調(diào)用。其實這種情況我們還是應(yīng)該覆蓋equals的方法的底洗,將equals方法設(shè)置成不可訪問的腋么。像下面這樣:
@Override
public boolean equals(Object o) {
throw new AssertionError();
}
3. 需要覆蓋equals方法的情況
一般來說,“值類”都是需要覆蓋equals方法的亥揖。
什么類屬于“值類”珊擂?
對于那些只關(guān)心內(nèi)容,不關(guān)心是否指向同一片內(nèi)存空間的類费变,都屬于“值類”摧扇。
注意:有一種“值類”不需要覆蓋equals方法,那就是單例挚歧。也就是說扛稽,如果一個類,它又是單例又是“值類”的話滑负,它就不需要覆蓋equals方法在张。
4. 在覆蓋equals方法時我們需要遵行的規(guī)范
(1)自反性:
即對于一個非空對象x,x.equals(x)必須返回true橙困。
(2)對稱性:
即對于非空的對象x瞧掺、y,如果x.equals(y)返回true的話凡傅,則y.equals(x)則必須返回true。
(3)傳遞性:
即對于非空的對象x肠缔、y夏跷、z,如果x.equals(y)返回true明未,y.equals(z)返回true槽华,則x.eqauls(z)則必須返回true。
(4)一致性:
即對于非空對象x趟妥,y猫态,只要equals方法的中比較的字段沒有被修改,那么x.equals(y)不管執(zhí)行多少次都是返回true,或都是返回false亲雪。
(5)和null相比必須返回false:
即對于非空對象x勇凭,x.equals(null)必須返回false;
5. 實現(xiàn)高質(zhì)量equals方法的訣竅
(1)用==操作符來檢查“參數(shù)是否是這個對象的引用”义辕。如果是虾标,則返回true。
這樣做是為了提高性能灌砖。
(2)使用instanceof操作符來檢查“參數(shù)是否為真確類型”璧函。如果不是,則返回false基显。
“正確類型”一般指的是equals方法所在的類蘸吓。有些情況是指該類所實現(xiàn)的某個接口。
(3)把參數(shù)轉(zhuǎn)化為真確的類型撩幽。
在被instanceof檢測過后库继,我們就將Object強行轉(zhuǎn)換成上面所提到的“正確的類型”,instanceof保證了我們轉(zhuǎn)換的真確性摸航。
(4)對于該類中的每個關(guān)鍵域(字段)制跟,檢查參數(shù)中的域是否與該對象中所對應(yīng)的域想匹配。
強轉(zhuǎn)之后酱虎,就可以開始匹配兩個對象中的字段了雨膨。如果匹配成功就可以返回true,如果“正確的類型”是一個接口读串,那么需要接口提供方法來訪問這些字段聊记,如果是個類的話,那就不用說了恢暖。
字段匹配技巧:
a排监、如果是非float和double類型的基本數(shù)據(jù)類型,那么直接使用==符號杰捂。
b舆床、如果是float和double,則使用Float.compare和Double.compare方法嫁佳。
c挨队、其他類型(也就是那些需要new出對象的類)則調(diào)用他們自身的equals方法。有些字段可能被允許為空蒿往,所以要進(jìn)行判斷盛垦,如下:
field == null ? o.field == null : filed.equal(0.field);
d、數(shù)組的話需要遍歷每一個元素進(jìn)行匹配瓤漏,匹配的時候參考上面的三條方法腾夯。
6. 覆蓋equals方法的時候我們還需要注意的地方
(1) 覆蓋equals的時候總是要覆蓋hashCode方法颊埃。(為什么覆蓋和怎么覆蓋會在下一篇文章講)
(2) 不要企圖讓equals方法過于智能。只是匹配對象的類型和對象中的各個參數(shù)的話很容易做到蝶俱,并且一般不會違反上面提到的規(guī)范班利。如果你過度的去尋求各種等價關(guān)系,那么上面的約定將很難遵守跷乐。
(4)覆蓋equals方法的時候請在方法前面加@Override
注解肥败。
本文到此結(jié)束