覆盖子类中的equals()和hashCode()...考虑超级字段

wj.*_*wj. 62 java inheritance overriding 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"))
Run Code Online (Sandbox Code Playgroud)

将返回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;
    }
    ...  
}
Run Code Online (Sandbox Code Playgroud)

如果你想看到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;
    }
}
Run Code Online (Sandbox Code Playgroud)

CPe*_*ins 56

儿童不应该检查父母的私人成员

很明显,所有重要的领域都应该考虑到平等和散列.

幸运的是,您可以轻松满足这两个规则.

假设您没有使用NetBeans生成的equals和hashcode,您可以修改Hominidae的equals方法以使用instanceof比较而不是类相等,然后直接使用它.像这样的东西:


    @Override  
    public boolean equals(Object obj) {  
        if (obj == null) { return false; }  
        if (getClass() != obj.getClass()) { return false; }  
        if (! super.equals(obj)) return false;
        else {
           // compare subclass fields
        }
Run Code Online (Sandbox Code Playgroud)

当然,哈希码很简单:


    @Override     
    public int hashCode() {     
        int hash = super.hashCode();
        hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);     
        hash = 89 * hash + (this.faceBookNickname != null ? this.faceBookNickname.hashCode() : 0);     
        return hash;     
    }     
Run Code Online (Sandbox Code Playgroud)

但是,严肃地说:NetBeans没有通过调用超类方法来考虑超类字段?

  • 我认为"孩子不应该检查父母的私人成员"是非常健全的父母建议. (47认同)
  • 这个`equals`方法不遵循[equals contract](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals%28java.lang.Object%29) .它不是对称的,因为`subclassInstance.equals(parentInstance)`由于getClass()检查而永远不会返回true,但在使用`super.equals`中隐含的假设是`parentInstance.equals(subclassInstance)`可以返回true. (16认同)
  • 如果 `super#equals` 的工作原理相同,`super.equals(obj)` 总是返回 `false`。 (2认同)

mat*_*t b 20

我更喜欢使用commons-lang包中的EqualsBuilder(和HashcodeBuilder)来使我的equals()和hashcode()方法更容易阅读.

例:

public boolean equals(Object obj) {
 if (obj == null) { return false; }
 if (obj == this) { return true; }
 if (obj.getClass() != getClass()) {
   return false;
 }
 MyClass rhs = (MyClass) obj;
 return new EqualsBuilder()
             .appendSuper(super.equals(obj))
             .append(field1, rhs.field1)
             .append(field2, rhs.field2)
             .append(field3, rhs.field3)
             .isEquals();
}
Run Code Online (Sandbox Code Playgroud)

  • 引用`.appendSuper()` 的荣誉。 (2认同)

Yis*_*hai 8

一般来说,跨子类实现equals很难保持对称和传递.

考虑到检查现场的超xy,和子检查x,yz.

所以Subclass == Superclass == Subclass,其中z在Subclass的第一个实例和第二个实例之间是不同的,违反了契约的传递部分.

这就是为什么equals的典型实现将检查getClass() != obj.getClass()而不是执行instanceof.在上面的示例中,如果SubClass或Superclass执行instanceof检查,它将破坏对称性.

所以结果是子类当然可以考虑super.equals(),但也应该进行自己的getClass()检查以避免上述问题,然后另外检查自己字段上的equals.它将是一个类的奇怪的鸭子,它根据超类的特定字段改变了自己的等于行为,而不仅仅是超类返回等于.


rod*_*oap 6

规则是:

  • 它是自反的:对于任何非空引用值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().

因此,请使用完成规则所需的字段.