[英]How to override the (final) equals method in java enums?
我在覆蓋Enum中的equals方法時遇到問題,使其與其他類兼容。 Enum實現了一個接口,其思路是可以測試此接口的所有實現是否相等,無論其類型如何。 例如:
public interface Group {
public Point[] getCoordinates();
}
public enum BasicGroups implements Group {
a,b,c; // simplified, they actually have constructors
// + fields and methods
}
public class OtherGroup implements Group {
// fields and methods
}
如果BasicGroup
和OtherGroup
具有相同的坐標(按任意順序),則equals方法應返回true。
執行myOtherGroup.equals(BasicGroup.a)
時沒問題,但由於Enums中的equals方法是final,我無法覆蓋它們。
有辦法解決這個問題嗎? 就像在另一個BasicGroup上測試時一樣,使用默認的equals方法(引用相等) ,並且在測試其他類時使用我自己的實現。 當我做BasicGroup.a.equals(myOtherGroup)
時,如何確保java不使用錯誤的?
你不能 @Override
一個final
方法( §8.4.3.3 ); 這很清楚。 enum
類型(第8.9節 )在Java中被非常特殊地處理,這就是為什么equals
是final
(也就是clone
, hashCode
等)。它根本不可能@Override
enum
的equals
方法,也不是你真的想要的更典型的使用場景。
但是 ,從整體來看,看起來您正在嘗試遵循Effective Java 2nd Edition中建議的模式,第34項:使用接口模擬可擴展枚舉 (有關enum
更多信息,請參閱語言指南 ):
您已定義此interface
(現在已明確記錄了預期的equals
行為):
public interface Group implements Group {
public Point[] getCoordinates();
/*
* Compares the specified object with this Group for equality. Returns true
* if and only if the specified object is also a Group with exactly the same
* coordinates
*/
@Override public boolean equals(Object o);
}
當然, interface
定義實現者的equals
方法應該如何表現是完全可以接受的。 這正是例如List.equals
的情況。 空LinkedList
equals
空ArrayList
,反之亦然,因為這是interface
要求的。
在您的情況下,您已選擇將某個Group
實現為enum
。 不幸的是,你現在不能按照規范實現equals
,因為它是final
,你不能@Override
它。 但是,由於目標是遵守Group
類型 ,因此可以通過具有ForwardingGroup
來使用裝飾器模式 ,如下所示:
public class ForwardingGroup implements Group {
final Group delegate;
public ForwardingGroup(Group delegate) { this.delegate = delegate; }
@Override public Point[] getCoordinates() {
return delegate.getCoordinates();
}
@Override public boolean equals(Object o) {
return ....; // insert your equals logic here!
}
}
現在,不是將enum
常量直接用作Group
,而是將它們包裝在ForwardingGroup
的實例中。 現在,此Group
對象將具有所需的equals
行為,如interface
所指定。
也就是說,而不是:
// before: using enum directly, equals doesn't behave as expected
Group g = BasicGroup.A;
你現在有類似的東西:
// after: using decorated enum constants for proper equals behavior
Group g = new ForwardingGroup(BasicGroup.A);
enum BasicGroups implements Group
的事實,即使它本身不遵循Group.equals
的規范,也應該非常清楚地記錄 。 必須警告用戶必須將常量包裝在ForwardingGroup
以獲得正確的equals
行為。
另請注意,您可以緩存ForwardingGroup
實例,每個enum
常量一個。 這有助於減少創建的對象數量。 根據Effective Java 2nd Edition,第1項:考慮靜態工廠方法而不是構造函數 ,您可以考慮讓ForwardingGroup
定義static getInstance(Group g)
方法而不是構造函數,允許它返回緩存實例。
我假設Group
是一個不可變類型( Effective Java 2nd Edition,Item 15:Minimize mutability ),否則你可能不應該首先使用enum
實現它。 鑒於此,請考慮Effective Java 2nd Edition,Item 25:Prefer list to arrays 。 您可以選擇讓getCoordinates()
返回List<Point>
而不是Point[]
。 您可以使用Collections.unmodifiableList
(另一個裝飾器!),這將使返回的List
不可變。 相比之下,由於數組是可變的,因此在返回Point[]
時,您將被迫執行防御性復制。
在Java中不可能這樣做。 (當涉及到方法時,final關鍵字的唯一目的是防止覆蓋!)
Enums上的equals
和一些其他方法是最終的,因此您無法更改它們的行為。 (你不應該 :)這是我對相關問題的回答 :
處理枚舉常量的客戶端的直覺是,當且僅當它們是相同的常量時,兩個常量是equal
。 因此,除了return this == other
任何其他實現將是違反直覺和容易出錯的。
相同的推理適用於hashCode()
, clone()
, compareTo(Object)
, name()
, ordinal()
和getDeclaringClass()
。
JLS並沒有激勵選擇讓它成為最終版本,但在這里的枚舉語中提到了相同的內容。 片段:
Enum中的equals方法是一個最終方法,它只在其參數上調用super.equals並返回結果,從而執行身份比較。
您可以通過調用方法hasSameCoordinatesAs或類似方法而不是equals來解決此問題。
enums的equals在語言規范中定義,因此您無法重新定義它。
平等是相當難以捉摸的。 不同的背景需要不同的平等關系。 通過在Object上使用equals()方法,Java強加了“內在”相等性,而像Set這樣的API依賴於它。
同時,排序不被視為“內在的”,兩個對象可以在不同的上下文中以不同的方式排序,並且API通常允許我們提供comprator,即自定義排序關系。
這是有趣的。 在數學術語中,平等與秩序一樣,只是一種關系,並且可以存在不同的平等關系。 “內在平等”的概念並不神聖。
所以我們也有一個Equal-ator,並更改API以接受自定義的平等關系:
interface Equalator
boolean equal(a, b)
public HashSet( Equalator equalator )
實際上,我們可以圍繞當前集合API構建包裝器,並添加新的相等功能。
這可能會回答您的問題。 為什么你首先依賴於equals()? 你可以刪除它,並依賴“equalator”嗎? 然后你就定了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.