在超类或子类中重写equals和hashCode方法或在重写中都覆盖

问题描述:

我对java编程相对较新,并且在找到使用位置时遇到问题 equals和hashcode方法覆盖当我有一个从子类继承的子类时超类。在超类或子类中重写equals和hashCode方法或在重写中都覆盖

我想检查超类和子类的对象是否相等,并且想知道超类和子类中的任何一个或两者是否需要它们的equals和hashcode方法重写?

我的子类没有实例变量,我超有2个实例变量(整数)

我的子类的构造函数是调用父类的构造。

如果我想重写子类equals和hashcode方法,可能基于这样的事实,即子类没有实例变量,但从它的超类继承了2个实例变量?

这实际上提出了一个难题。假设你有一个Foo类和两个子类FooA和FooB。是否有意义,在您的应用程序/域中,FooA永远等于Foo还是FooB?

如果是这样,你应该在超类中实现equals。并测试instanceof Foo。基本上,在FooA或FooB中添加的任何额外字段都将被忽略。通常这是正确的。代码如下所示:

public boolean equals(Object o) { // perfectionists will make this final 
    if (this == o) 
    return true; 
    if (o instanceof Foo) { // note that Foo, FooA and FooB would all pass 
    Foo oFoo = (Foo)o; 
    // compare all the fields of Foo here 
    } 

    return false; 
} 

如果不是,则需要在子类中实现equals。测试类是等于,而不仅仅是instanceof。例如

public boolean equals(Object o) { 
    if (this == o) 
    return true; 
    if (o == null) // this extra check is needed to avoid a NPE 
    return false; 
    if (o.getClass() == this.getClass()) { // must be an exact match 
    FooA oFoo = (FooA)o; 
    // compare all the fields here 
    } 

    return false; 
} 

总的来说,我认为大多数人使用第一种方法。它似乎最适合你的问题。见Josh Bloch的Effective Java。你会发现很多帖子,例如Any reason to prefer getClass() over instanceof when generating .equals()?

+0

感谢user949300,上面的和有效的Java书籍章节非常有用。戴夫 – daveb

你需要重写他们的阶级,谁的对象将是下equals()检查在运行时或者其对象将/可根据散列基于数据结构

由于没有在子类中增加了新的属性,覆盖在超类中的equals()hashcode()会没事的。当您在子类对象上调用这些方法时,超类方法将被称为不是来自类Object

但是,如果在以后的日期将新属性添加到子类中,则还需要重写子类中的这些方法。

如果我要重写子类的equals和hashCode方法是 可能基于以下事实:子类没有实例变量,但 继承自其超2个实例变量?

肯定是可能,但它很少有意义。请注意,equals()的合同要求它是对称的,即a.equals(b)b.equals(a)应始终具有相同的结果。当ab是以不同的方式定义equals()的子类和超类的实例时,该合约可能不会保留。这意味着如果您将两个类的实例放入集合中,集合可能无法正常工作。