[英]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.