我的 equals() 不满足 equals() 总合同的哪一部分

Which part of the equals() general contract does my equals() not satisfy

我是 java 的新手,我只是想了解 @Overrideequals()hashcode() 方法。
我知道要使 equals 方法正确,它必须是:

  1. 自反: a.equals(a)
  2. 对称: a.equals(b) 然后 b.equals(a)
  3. 传递: a.equals(b) && b.equals(c) 然后 a.equals(c)
  4. 不为空: ! a.equals(null)

在编写我对 equals 方法的覆盖时,我正在努力确定我对上述哪些属性感到满意和不满意。

我知道eclipse可以为我生成这些,但是由于我还没有完全理解这个概念,写出来帮助我学习。

我已经写出了我认为正确的方法,但是当我检查 eclipse 生成的版本时,我似乎 'missing' 某些方面。

示例:

public class People {

    private Name first; //Invariants --> !Null, !=last
    private Name last;  // !Null, !=first
    private int age;    // !Null, ! <=0
    ...
}

我写的:

public boolean equals(Object obj){
    if (obj == null){
        return false;
    }
    if (!(obj instanceof People)){
         return false;
    }
    People other = (People) obj;
    if (this.age != other.age){
        return false;
    }
    if (! this.first.equals(other.first)){
        return false;
    }
    if (! this.last.equals(other.last)){
        return false;
    }
    return true;
}

vs eclipse 生成

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;

    People other = (People) obj;
    if (first == null) {
        if (other.first != null)
            return false;
    } else if (!first.equals(other.first))
        return false; 
    if (age != other.age)
        return false;
    if (last == null) {
        if (other.last != null)
            return false;
    } else if (!last.equals(other.last))
        return false;

    return true;
}

我失踪了:

我不确定 getClass() 是什么,我的实现是否不正确?

我不认为你的实现有误,但有几点要注意:

if (this == obj)
      return true;

是一个性能优化,它直接测试参考相等性和短路测试,其中a a.

if (getClass() != obj.getClass())
        return false;

类似于您的 instanceof 调用,优化了空检查。其他调用似乎是空检查。

第一段代码:

if (this == obj)
    return true;

如果您将对象引用与自身进行比较,这会提高性能。示例:a.equals(a);.

第二段代码:

if (getClass() != obj.getClass())
    return false;

这会比较被比较的引用的 class 是否与 this 的 class 相同。使用此方法与 instanceof 的区别在于,与子 class 相比,它的限制更为严格。示例:

public class Foo { }
public class Bar extends Foo { }

//...
Foo foo = new Bar();
System.out.println(foo instanceof Bar); //prints true
System.out.println(foo instanceof Foo); //prints true
Foo foo2 = new Foo();
System.out.println(foo.getClass() == foo2.getClass()); //prints false

你应该选择哪一个?方法没有好坏之分,这取决于你想要的设计。

第三段代码:

if (first == null) {
        if (other.first != null)
            return false;
    } else if (!first.equals(other.first))
        return false; //For each variable.

这只是对 class 中每个对象引用字段的空检查。请注意,如果 this.firstnull 那么执行 this.first.equals(...) 将抛出 NullPointerException.

你不需要写

if (obj == null){
        return false;
}
if (!(obj instanceof People)){
     return false;
}

因为 null 总是在 instanceof 检查中给出 false。所以这些行可以简化为

if (!(obj instanceof People)){
     return false;
}

至于你的主要问题是你的方法是否满足 equals() 方法的要求,严格来说答案是否定的,或者至少它可能是不可靠的。这是因为可以按如下方式扩展 class

public class SpecialPeople extends People {

    // code omitted

    @Override
    public boolean equals(Object object) {
        if (object == null || object.getClass() != getClass())
            return false;
        SpecialPeople other = (SpecialPeople) object;
        return other.getAge() == getAge() 
                && other.getFirst().equals(getFirst()) 
                && other.getLast().equals(getLast());
}

现在假设 aPeople 的实例并且 bSpecialPeople 的实例。还假设 ab 具有相同的名字和年龄。然后

a.equals(b) == true  // instanceof check succeeds
b.equals(a) == false // getClass() check fails

因此equals()不对称!出于这个原因,如果您在 equals() 中使用 instanceof 而不是 getClass(),您应该使 equals() 方法 final 或 class final