是否有一个特定的规则如何覆盖 equals()
& hashCode()
在 sub classes 考虑 super fields ??知道有很多参数:超级字段是私有/公共的,有/无getter ...
例如,Netbeans生成的equals()&hashCode()将不考虑超级字段......和
new HomoSapiens("M", "80", "1.80", "Cammeron", "VeryHot").equals(
new HomoSapiens("F", "50", "1.50", "Cammeron", "VeryHot"))
将返回true :(
public class Hominidae {
public String gender;
public String weight;
public String height;
public Hominidae(String gender, String weight, String height) {
this.gender = gender;
this.weight = weight;
this.height = height;
}
...
}
public class HomoSapiens extends Hominidae {
public String name;
public String faceBookNickname;
public HomoSapiens(String gender, String weight, String height,
String name, String facebookId) {
super(gender, weight, height);
this.name = name;
this.faceBookNickname = facebookId;
}
...
}
如果你想看到Netbeans生成的equals()和hashCode():
public class Hominidae {
...
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Hominidae other = (Hominidae) obj;
if ((this.gender == null) ? (other.gender != null) : !this.gender.equals(other.gender)) {
return false;
}
if ((this.weight == null) ? (other.weight != null) : !this.weight.equals(other.weight)) {
return false;
}
if ((this.height == null) ? (other.height != null) : !this.height.equals(other.height)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
hash = 37 * hash + (this.gender != null ? this.gender.hashCode() : 0);
hash = 37 * hash + (this.weight != null ? this.weight.hashCode() : 0);
hash = 37 * hash + (this.height != null ? this.height.hashCode() : 0);
return hash;
}
}
public class HomoSapiens extends Hominidae {
...
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final HomoSapiens other = (HomoSapiens) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if ((this.faceBookNickname == null) ? (other.faceBookNickname != null) : !this.faceBookNickname.equals(other.faceBookNickname)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 89 * hash + (this.faceBookNickname != null ? this.faceBookNickname.hashCode() : 0);
return hash;
}
}
10 回答
Children should not examine the private members of their parents
但显然,所有重要的领域都应该考虑到平等和散列 .
幸运的是,您可以轻松满足这两个规则 .
假设您没有使用NetBeans生成的equals和hashcode,您可以修改Hominidae的equals方法以使用instanceof比较而不是类相等,然后直接使用它 . 像这样的东西:
当然,哈希码很简单:
但是,严肃地说:NetBeans没有通过调用超类方法来考虑超类字段?
我更喜欢使用commons-lang package中的EqualsBuilder(和HashcodeBuilder)来使我的equals()和hashcode()方法更容易阅读 .
例:
一般来说,跨子类实现equals很难保持对称和传递 .
考虑一个超类检查字段
x
和y
,子类检查x
,y
和z
.所以Subclass == Superclass == Subclass,其中z在Subclass的第一个实例和第二个实例之间是不同的,违反了 Contract 的传递部分 .
这就是为什么equals的典型实现将检查
getClass() != obj.getClass()
而不是执行instanceof . 在上面的示例中,如果SubClass或Superclass执行instanceof检查,它将破坏对称性 .所以结果是一个子类当然可以考虑super.equals(),但也应该进行自己的getClass()检查以避免上述问题,然后另外检查其自己的字段上的equals . 它将是一个类的奇怪的鸭子,它根据超类的特定字段改变了自己的等于行为,而不仅仅是超类返回等于 .
规则是:
它是自反的:对于任何非空引用值x,x.equals(x)应该返回true .
它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true .
它是传递的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true .
它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是未修改对象的equals比较中使用的信息 .
对于任何非空引用值x,x.equals(null)应返回false .
通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相等的哈希代码
来自Object.equals() .
因此,请使用完成规则所需的字段 .
因为继承会破坏封装,所以实现equals()和hashCode()的子类必然会考虑其超类的特殊性 . 我已成功编码从子类的方法调用父类的equals()和hashCode()方法 .
关于接受的@CPerkins答案,我认为给定的equals()代码不会可靠地运行,因为super.equals()方法也可能检查类是否相等 . 子类和超类不具有相同的类 .
听起来你的父(超级)类不会覆盖equals . 如果是这种情况,则在子类中重写此方法时,需要比较父类中的字段 . 我同意使用公共EqualsBuiler是可行的方法,但你需要注意不要破坏等于 Contract 的对称/转换部分 .
如果您的子类将属性添加到父类,并且父类不是抽象的并且覆盖等于您将会遇到麻烦 . 在这种情况下,您应该真正关注对象组合而不是继承 .
我强烈推荐Joshua Block关于Effective Java的部分 . 它是全面的,非常好解释 .
那么,
HomoSapiens#hashcode
就足以满足CPerkins的答案了 .如果您希望这些父项的字段(
gender
,weight
,height
)正在运行,则一种方法是创建父类型的实际实例并使用它 . 感谢上帝,这不是一个抽象的课程 .我正在添加一种方法(我认为)解决这个问题 . 关键是添加一个方法松散地检查相等性 .
这里来了
Child
.测试...
值得注意的是,IDE自动生成可能已经考虑了超类,只要提供了超类的equals()和hashCode() . 也就是说,应首先自动生成super这两个函数,然后自动生成子元素 . 我在Intellj Idea下面得到了正确的例子:
问题发生在你不首先自动生成超级的时候 . 请在Netbeans下方查看 .
我相信他们现在有一种方法可以为你做到这一点:
EqualsBuilder.reflectionEquals(this,o);
HashCodeBuilder.reflectionHashCode(本);