重写 equals() &子类中的 hashCode() ...考虑超级字段
是否有关于如何覆盖 equals()
& 的具体规则? 子类中的hashCode()
考虑到超级字段?知道有很多参数:超级字段是私有/公共的,有/没有 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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
孩子不应该检查其父母的私有成员
但是显然,所有重要字段都应该考虑到平等和散列。
幸运的是,您可以轻松满足这两个规则。
假设您没有被 NetBeans 生成的 equals 和 hashcode 所困扰,您可以修改 Hominidae 的 equals 方法以使用 instanceof 比较而不是类相等,然后直接使用它。像这样的事情:
当然,哈希码很简单:
不过说实话:NetBeans 不通过调用超类方法来考虑超类字段是怎么回事?
Children should not examine the private members of their parents
But obviously, all significant fields should be taken into account for equality and hashing.
Fortunately, you you can easily satisfy both rules.
Assuming you're not stuck using the NetBeans-generated equals and hashcode, you can modify Hominidae's equals method to use instanceof comparison rather than class equality, and then use it straightforwardly. Something like this:
Of course, hashcode is easy:
Seriously, though: what's up with NetBeans not taking superclass fields into account by calling the superclass methods?
我更喜欢使用 EqualsBuilder (和 HashcodeBuilder)来自 commons-lang 包 使我的 equals() 和 hashcode() 方法成为更容易阅读。
例子:
I prefer to use EqualsBuilder (and HashcodeBuilder) from the commons-lang package to make my equals() and hashcode() methods a lot easier to read.
Example:
一般来说,跨子类实现 equal 很难保持对称性和传递性。
考虑一个检查字段
x
和y
的超类,以及检查x
、y
和的子类z 。
因此,子类 == 超类 == 子类,其中子类的第一个实例和第二个实例之间的 z 不同,违反了契约的传递部分。
这就是为什么 equals 的典型实现会检查
getClass() != obj.getClass()
而不是执行 instanceof。在上面的例子中,如果子类或超类进行instanceof检查,它将破坏对称性。因此,结果是子类当然可以考虑 super.equals(),但也应该执行自己的 getClass() 检查以避免上述问题,然后另外检查其自己的字段是否等于。如果一个类根据超类的特定字段而不是仅仅根据超类返回 equals 来改变自己的 equals 行为,那将是一个奇怪的鸭子。
Generally speaking implementing equals across subclasses is hard to keep symmetric and transitive.
Consider a superclass that checks for field
x
andy
, and subclass checks forx
,y
andz
.So a Subclass == Superclass == Subclass where z is different between the first instance of Subclass and the second, violating the transitive part of the contract.
This why the typical implementation of equals will check for
getClass() != obj.getClass()
instead of doing an instanceof. In the above example, if SubClass or Superclass does an instanceof check it would break symmetry.So the upshot is that a subclass can certainly take into account super.equals() but should also do its own getClass() check to avoid the above issues and then check for equals on its own fields in addition. It would be a strange duck of a class that changed its own equals behavior based on specific fields of the superclass rather than just if the superclass returns equals.
规则是:
来自 Object.equals()。
因此,请使用满足规则所需的字段。
The rules are:
from Object.equals().
So, use the fields needed to fulfill the rules.
好吧,
HomoSapiens#hashcode
对于 CPerkins 的回答就足够了。如果您希望这些父级字段(
gender
、weight
、height
)发挥作用,一种方法是创建父级类型的实际实例并使用它。感谢上帝,它不是一个抽象类。我正在添加一种方法来(我认为)解决这个问题。关键点是添加一个松散地检查相等性的方法。
孩子
来了。测试...
Well,
HomoSapiens#hashcode
will be enough with CPerkins's answer.If you want those parent's fields(
gender
,weight
,height
) in action, one way is creating an actual instance of parent type and use it. Thank God, it's not an abstract class.I'm adding a way to (I think) solve this. The key point is adding a method loosely checks the equality.
And here comes the
Child
.Testing...
关于接受的 @CPerkins 答案,我认为给定的 equals() 代码不会可靠地工作,因为 super.equals() 方法也可能检查类相等性。一个子类&超类不会有相等的类。
Regarding the accepted @CPerkins answer, I don't think the given equals() code will work reliably, due to the likelihood that the super.equals() method will also check for class equality. A subclass & superclass will not have equal classes.
值得注意的是,IDE 自动生成可能已经考虑了超类,只要超类的 equals() 和 hashCode() 还存在即可。也就是说,应该先自动生成super的这两个函数,然后再自动生成child。我在 Intelllj Idea 下得到了下面的正确示例:
当您首先不自动生成超级时,问题就会发生。请在 Netbeans 下检查上面的内容。
It's worth noting that the IDE auto generation maybe has taken into consideration super class,just provided that the equals() and hashCode() of super class exists yet. That is, should auto generate these two functions of super first, and then auto generate of the child. I got below right example under Intellj Idea:
The problem happens just when you don't auto generate super's in first. Please check above under Netbeans.
因为继承破坏了封装,所以实现 equals() 和 hashCode() 的子类必须考虑其超类的特殊性。我已经成功地从子类的方法对父类的 equals() 和 hashCode() 方法进行编码调用。
Because inheritance breaks encapsulation, subclasses that implement equals() and hashCode() must, necessarily, account for the peculiarities of their superclasses. I've had success encoding calls to the parent class's equals() and hashCode() methods from the subclass's methods.
听起来你的父(超级)类没有覆盖 equals 。如果是这种情况,那么当您在子类中重写此方法时,您需要比较父类中的字段。我同意使用公共 EqualsBuiler 是可行的方法,但您确实需要小心,不要破坏 equals 合约的对称/传递部分。
如果你的子类向父类添加属性,而父类不是抽象的并且重写了 equals,你就会遇到麻烦。在这种情况下,您应该真正考虑对象组合而不是继承。
我强烈推荐 Joshua Block 的《Effective Java》中关于此的部分。它很全面并且解释得很好。
It sounds like your parent (super) class doesn't override equals. If this is the case then you need to compare the fields from the parent class when you override this method in the sub-class. I agree that using the commons EqualsBuiler is the way to go but you do need to be careful that you don't break the symmetry/transative portions of the equals contract.
If your sub-class adds attributes to the parent class and the parent class isn't abstract and overrides equals you're going to get in to trouble. In this scenario you should really look at object composition instead of inheritance.
I'd strongly recommend the section in Effective Java by Joshua Block on this. It's comprehensive and really well explained.
我相信他们现在有一个方法可以为您做到这一点:
EqualsBuilder.reflectionEquals(this, o);
HashCodeBuilder.reflectionHashCode(this);
I believe they now have a method that just does this for you :
EqualsBuilder.reflectionEquals(this, o);
HashCodeBuilder.reflectionHashCode(this);