當我讀到一本Java書時,作者曾經說過,在設計一個類時,使用equals()
來繼承是非常不安全的。例如:爲什麼我不應該用繼承來使用equals?
public final class Date {
public boolean equals(Object o) {
// some code here
}
}
在上面的類,我們應該把final
,所以其他類不能從這個繼承。而我的問題是,爲什麼當它允許另一個類繼承它是不安全的?
當我讀到一本Java書時,作者曾經說過,在設計一個類時,使用equals()
來繼承是非常不安全的。例如:爲什麼我不應該用繼承來使用equals?
public final class Date {
public boolean equals(Object o) {
// some code here
}
}
在上面的類,我們應該把final
,所以其他類不能從這個繼承。而我的問題是,爲什麼當它允許另一個類繼承它是不安全的?
因爲很難(不可能?)使它正確,尤其是symmetric property。
假設您有Vehicle
類和Car extends Vehicle
類。 Vehicle.equals()
如果參數也是Vehicle
並且具有相同的權重,則產生true
。如果你想實現Car.equals()
它應該產生true
僅當參數也是一個車,除了重量外,還應做比較,發動機等
現在想象一下下面的代碼:
Vehicle tank = new Vehicle();
Vehicle bus = new Car();
tank.equals(bus); //can be true
bus.equals(tank); //false
如果通過重合坦克和公共汽車具有相同的重量,第一次比較可能產生true
。但由於坦克不是汽車,因此將它與汽車相比總會產生false
。
你有一些變通辦法:
嚴格:兩個對象相等當且僅當他們有完全相同的類型(以及所有屬性都相等)。這很糟糕,例如當你僅僅爲了添加一些行爲或裝飾原始類而進行子類化時。一些框架也在不需要注意的情況下繼承類(Hibernate,使用CGLIB代理的Spring AOP ...)
鬆散:如果兩個對象的類型「兼容」並且它們具有相同內容(語義上),則兩個對象相等。例如。如果它們包含相同的元素,則兩個集合是相等的,一個是HashSet
而另一個是TreeSet
(感謝@veer用於指出)並不重要。
這可能會引起誤解。取兩個LinkedHashSet
(其中插入順序作爲合同的一部分)。然而,由於equals()
只需要原料Set
合同考慮,比較收益率true
即使是明顯不同的對象:
Set<Integer> s1 = new LinkedHashSet<Integer>(Arrays.asList(1, 2, 3));
Set<Integer> s2 = new LinkedHashSet<Integer>(Arrays.asList(3, 2, 1));
System.out.println(s1.equals(s2));
不*不可能*;見例如['Set.equals'](http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#equals(java.lang.Object)) – oldrinb
@veer:我更新了我的回答,謝謝。 –
@TomaszNurkiewicz作爲你的鏈接給我,如果我們使用if(this.getClass()!= tank.getClass()){return false;}或if(this.getClass()!= tank.getClass() ){return false;}',問題就解決了。你能告訴我更多關於這個案子嗎? – hqt
馬丁·奧德斯基(中Java中泛型的背後人物以及當前的原始代碼庫)在他的書中有一個很好的章節編程Scala解決這個問題。他建議添加一個canEqual
方法可以解決相等/繼承問題。你可以在他的書的第一版,這是可以在線閱讀的討論:
Chapter 28 of Programming in Scala, First Edition: Object Equality
這本書當然是指斯卡拉的,但同樣的想法適用於經典的Java。對於來自Java背景的人來說,示例源代碼不應太難理解。
編輯:
它看起來像Odersky的早在2009年發表了在Java中同一概念的文章,它可在同一網站上:
How to Write an Equality Method in Java
我真的不要以爲在這個答案中總結這篇文章會做正義。它涵蓋了深入討論對象平等的主題,從平等實現中的常見錯誤到Java equals
作爲等價關係的全面討論。你應該真的只是讀它。
'Comparable'指定'compareTo',而不是'equals'。 – oldrinb
哦。謝謝:)我編輯過:D – hqt
這本書叫什麼名字? –