Effective Java之覆盖equal时要遵守通用约定(八)
先介紹一下Object的equal作用,==代表物理上的相等,equal代表邏輯上的相等,Object的equal的方法其實等同于==,這是因為它的邏輯是“如果對象物理相等,那么它們就邏輯相等”。
?
1.何時不需要覆蓋
1.如果每個實例的本質是唯一的,也就是說只有自己才會等于自己,那么它的equal方法應該相當于它的==,所以它從Object繼承過來的方法剛好滿足條件了,不需要覆蓋。
2.不關心它的“邏輯相等”,既然都不關心了,那還寫什么?
3.超類覆蓋的equal方法,對子類同樣適用的情況下,就不用覆蓋了。比如Set實現了從AbstractSet繼承的方法,所以它不用去覆蓋了。
?
2.何時需要覆蓋
1.有的類的equal永遠也不會調用的情況,那么應該覆蓋equals方法,讓它在調用時拋出錯誤。
2.如果希望定義特有的”邏輯相等”的情況,可以覆蓋equals,比如定義市民類,如果兩個市民的身份證字段相等,那么兩個市民類相等,這樣的邏輯。
?
3.覆蓋需要遵守的約定
在覆蓋equals方法時,必須遵守它的通用約定:
1)自反性: x.equals(x) 必須返回true 。實例自身必然邏輯相等。
2)對稱性: x.equals(y) 與 y.equals(x) 返回結果應該相同,同為true或者同為false
3)傳遞性: x.equals(y)返回true,y.equals(z)返回true,則x.equals(z)應該返回true。
4)一致性: 只要比較的實例對象的關鍵屬性值沒有改變 ,那么無論調用多少次equals方法返回的結果都應該相同,一致。
5)對于非null的x實例,x.equals(null) 永遠返回false。
?
這一章的內容十分地充實,這里,我只能總結一下書中重要的內容:
1.不要企圖讓一個類和一個它的非子類進行equal對比,比如 市民類.equal(String identity),
希望只要市民的身份證號等于字符串類型的identity就返回true,這樣是不可行的,因為必然會違反對稱性,除非你能去修改String類?
2.我們無法在擴展可實例化的類的同時,既增加新的值組件,同時又保留equal約定。
也就是遇到可實例化的父類和子類,而且子類擴展了父類的問題時,會遇到很尷尬的問題,這里應該認真看一下書~
書中寫到了父類和子類的各種糾纏~解決的一種方法,也可以說是權宜之計,就是割斷父子關系。。
也就是利用復合優于繼承的原則;原來的子類不是擴展了父類嗎,那么我讓父類成為原來子類的一個私有域,利用復合的方式組裝一個類出來。既然不存在父子關系了,父子進行對比產生的種種糾纏也就不復存在了。
書中也有舉到一個很有意思的例子,TimeStamp對Date進行擴展,增加了nanoseconds域,由于上面的規則“我們無法在擴展可實例化的類的同時,既增加新的值組件,同時又保留equal約定”,所以設計師也無法進行正確的操作,于是TimeStamp有個免責聲明,告誡開發者不要同時使用TimeStamp和Date,也就是不讓程序員糾纏在父子的問題上了。
這里有個里式替換原則,可以注意一下:一個類型的任何重要屬性也將適用于它的子類型,因此為該類型編寫的任何方法,在他的子類型也應該同樣運行得很好。
?
4.如何使用?
1.先用“==”操作符號判斷“參數是否為這個對象的引用”,如果是,那直接返回true。
這其實是一種性能優化,不進行這個操作也會得到一樣的結果,所以需要根據每次比較的代價判斷是否先用“==”,代價大就需要優化。
2.用instanceof檢查“參數是否為正確的類型”。
3.再將參數object對象轉成正確的類型。
4.自己定義“邏輯相等”。
5.寫完有仔細思考有沒有滿足對稱性,傳遞性,一致性。
例子:
public class Citizen {private String name ;private String Identity;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getIdentity() {return Identity;}public void setIdentity(String identity) {Identity = identity;}@Overridepublic boolean equals(Object obj) {if(this == obj) {return true;}if(!(obj instanceof Citizen)) {return false;}Citizen citizen = (Citizen)obj;return this.getIdentity().equals(citizen.getIdentity());}}這里的 先用“==”操作符號判斷“參數是否為這個對象的引用” 可以不需要。
總結
以上是生活随笔為你收集整理的Effective Java之覆盖equal时要遵守通用约定(八)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Effective Java之消除过期的
- 下一篇: Effective Java之避免使用终