[英]Reusable implementation of equals and hashCode
我正在一個項目中,其中許多類需要equals
和hashCode
適當典型實現:每個類具有一組最終字段,這些字段在構造時初始化為“深度”不可變的對象(在某些情況下,應接受null
)用於哈希和比較。
為了減少樣板代碼的數量,我考慮過編寫一個提供此類行為常見實現的抽象類。
public abstract class AbstractHashable {
/** List of fields used for comparison. */
private final Object[] fields;
/** Precomputed hash. */
private final int hash;
/**
* Constructor to be invoked by subclasses.
* @param fields list of fields used for comparison between objects of this
* class, they must be in constant number for each class
*/
protected AbstractHashable(Object... fields) {
this.fields = fields;
hash = 31 * getClass().hashCode() + Objects.hash(fields);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !getClass().equals(obj.getClass())) {
return false;
}
AbstractHashable other = (AbstractHashable) obj;
if (fields.length != other.fields.length) {
throw new UnsupportedOperationException(
"objects of same class must have the same number of fields");
}
for (int i=0; i<fields.length; i++) {
if (!fields[i].equals(other.fields[i])) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return hash;
}
}
打算這樣使用:
public class SomeObject extends AbstractHashable {
// both Foo and Bar have no mutable state
private final Foo foo;
private final Bar bar;
public SomeObject(Foo foo, Bar bar) {
super(foo, bar);
this.foo = Objects.requireNonNull(foo);
this.bar = bar; // null supported
}
// other methods, no equals or hashCode needed
}
在我看來,這是一種減少冗長但仍有效的equals
和hashCode
實現的簡單而有效的方法。 但是,由於我不記得曾經見過類似的東西(上面鏈接中的答案除外),所以我想特別問一下在應用之前是否有反對這種方法的觀點(或可能會有所改進)它貫穿整個項目。
我已經看到此方法有兩個問題:
AbstractHashable
extend
,您不再extend
從任何其他類extend
。 重用equals
和hashCode
付出了很高的代價。 通過將更多的元數據傳遞給AbstractHashable
類可以解決第一個問題,該類允許它標識哪些字段是可選的。 例如,您可以將另一個數組傳遞給AbstractHashTable
,該數組包含通過setter作為其元素被忽略的索引位置。 第二個問題可以通過使用Composition解決。 對其進行重構,而不是擴展AbstractHashTable
,以便它可以與其用戶建立HAS-A關系,而不是IS-A關系。
但是,由於我不記得曾經見過類似的東西(上面鏈接中的答案除外),所以我想特別問一下這種方法是否有針對性
這種方法肯定會影響代碼的可讀性。 如果您想出一種更具可讀性的方法(例如通過使用批注),那么我想重用equals
和hashCode
實現不會有任何問題。
綜上所述,諸如eclipse之類的現代IDE可以輕松為您生成equals
和hashCode
實現,因此,真的有必要提出這種解決方案嗎? 我相信不會 。
根據我的經驗,這似乎很糟糕,因為您會增加在運行時與編譯時可能遇到的錯誤(記住,在列表等中對這些對象的所有使用。現在可以給您帶來擴展的行為)。 如果類中字段的順序不同怎么辦? 其次,您濫用繼承嗎? Maybee選擇某種框架( https://projectlombok.org/ ),該框架會基於注釋生成哈希碼和等號?
該解決方案應該起作用。
但是,從OOP的角度來看,它有點弱:
現代IDE很容易生成此類方法,如果您願意,還可以使用框架(如Lombok)或庫(如Guava的Objects / Java 8的Objects)來簡化這些方法。
我建議看看apache的HashCodeBuilder和EqualsBuilder類。 它也具有基於反射的方法,例如reflectionHashCode和reflectionEquals。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.