当超类不重新声明equals()和hashCode()时会出现什么问题? [英] What will go wrong when superclass does not redeclare equals() and hashCode()?

查看:707
本文介绍了当超类不重新声明equals()和hashCode()时会出现什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有两个这样的类:

abstract class A { /* some irrelevant methods */ }

class B extends A {
    public final int x;

    public B(final int x) {
        this.x = x;
    }

    /* some more irrelevant methods */
}

然后我在类 equals()和 hashCode()方法> B 使用Eclipse的Source→Generate hashCode()和equals()......。但Eclipse警告我:

Then I generate the equals() and hashCode() methods on class B using Eclipse's "Source → Generate hashCode() and equals()...". But Eclipse warns me that:


超类'com.example.test2.A'不重新声明equals()和hashCode() - 生成的代码可能无法正常工作。

The super class 'com.example.test2.A' does not redeclare equals() and hashCode() - the resulting code may not work correctly.

因此,什么会导致生成的代码无法正常生成的代码?

(顺便说一下,生成的方法如下所示:

(BTW, the generated methods look like this:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + x;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    B other = (B) obj;
    if (x != other.x)
        return false;
    return true;
}

推荐答案

在覆盖等于遵守一组特定规则时必须小心。请参阅 javadoc 了解详情。简而言之,两个棘手的部分是保持对称性和传递性。根据Joshua Block的 Effective Java

You must be careful when overriding equals to adhere to a specific set of rules. See the javadoc for details. In short, two tricky parts are preserving symmetry and transitivity. According to Joshua Block's Effective Java

无法扩展可实例化的类并添加值组件,同时保留等于合同

"There is no way to extend an instantiable class and add a value component while preserving the equals contract"

这是什么意思?好吧,假设你在A类中有一个类型为T的属性,在子类B中有另一个类型为V的属性。如果两个类都重写等于那么当比较A到B而不是B到A时,你会得到不同的结果。

What does this mean? Well let's say you have in class A a property of type T and in subclass B another property of type V. If both classes override equals then you'll get different results when comparing A to B than B to A.

A a = new A(T obj1);
B b = new B(T obj1, V obj2);
a.equals(b) //will return true, because objects a and b have the same T reference.
b.equals(a) //will return false because a is not an instanceof B

这违反了对称性。如果你通过混合比较尝试纠正这个问题,你将失去传递性。

This is a violation of symmetry. If you try and correct this by doing mixed comparisions, you'll lose transitivity.

B b2 = new B(T obj1, V obj3);
b.equals(a) // will return true now, because we altered equals to do mixed comparisions
b2.equals(a) // will return true for the same reason
b.equals(b2) // will return false, because obj2 != obj3

在这种情况下b == a,b2 == a,b!= b2,这是一个问题。

In this case b == a, b2 ==a, b != b2, which is a problem.

编辑

为了更准确地回答这个问题:什么会导致生成的代码与生成的方法无法正常工作让我们考虑一下这个具体情况。父类是抽象的,不会覆盖equals。我相信我们可以得出结论,代码是安全的,并且没有发生违反平等合同的情况。这是父类是抽象的结果。它无法实例化,因此上面的示例不适用于它。

In an effort to more precisely answer the question: "what will make the resulting code not working correctly with the generated methods" let's consider this specific case. The parent class is abstract and does not override equals. I believe we can conclude that the code is safe and no violation of the equals contract has occurred. This is a result of the parent class being abstract. It cannot be instantiated, therefore the above examples do not apply to it.

现在考虑父类是具体的并且不重写equals的情况。正如Duncan Jones指出的那样,仍然会生成警告消息,在这种情况下,这样做似乎是正确的。默认情况下,所有类从Object继承equals,并将根据对象标识(即内存地址)进行比较。如果与一个覆盖等于的子类一起使用,这可能会导致不对称的比较。

Now consider the case when the parent class is concrete and does not override equals. As Duncan Jones pointed out, the warning message is still generated, and in this case seems correct to do so. By default, all classes inherit equals from Object, and will be compared based on object identify (i.e. memory address). This could result in a unsymmetrical comparison if used with a subclass that does override equals.

A a = new A();
B b = new B(T obj1);
a.equals(b) //will return false, because the references do not point at the same object
b.equals(a) //should return false, but could return true based on implementation logic. 

如果b.equals(a)因任何原因返回true,无论是实现逻辑还是编程错误,将导致失去对称性。编译器无法强制执行此操作,因此会生成警告。

If b.equals(a) returns true for whatever reason, either implementation logic or programming error, a loss of symmetry will result. The compiler has no way to enforce this, hence, a warning is generated.

这篇关于当超类不重新声明equals()和hashCode()时会出现什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆