这等于合法吗?

Is this equals legal?

我遇到过这段代码。我从未见过以这种方式实现的平等。让我印象深刻的是它真的是 "neat",从某种意义上说,它只需要一行样板文件。

但是,我以前从未见过这种方法,这让我很怀疑。根据Javaequals和hashCode的约定,下面的实现是否合法?

@Override
public boolean equals(Object o)
{
  return this == o || o instanceof DetailsPageTrackingRequest 
  && this.hashCode() == o.hashCode();
}

@Override
public int hashCode()
{
  //java.util.Objects
  return Objects.hash(pageTrackingRequest, searchId, productId);
}

由您来定义 class 的两个实例被视为彼此相等的标准。

但是,您应该考虑 pageTrackingRequestsearchIdproductId 属性的不同组合可能会产生相同的哈希码,您可能不想考虑这种不同组合彼此相等。 equals 要求所有 3 个属性分别彼此相等可能更有意义。

您应该单独检查 属性 值,而不是只检查 hashCode。有可能两个完全不同的 objects 导致相同的 hashCode 不相等。

此外,equals 不应仅依赖 hashCode,例如如果 hashCode 方法更改为以下内容:

@Override
public int hashCode()
{
    return 31;
}

equals 方法将开始为所有不应出现这种情况的对象返回 true

这种做法是错误的。哈希码相等性不是决定性的,因为不相等的对象可能具有相同的哈希值。这是一个工程内置错误。

由于其他答案中已经说明的原因,这可能不是一个好主意。

至于 "legal" 方面,Contract of Object.equals 陈述

The equals method implements an equivalence relation on non-null object references:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

一步一步:

  • 自反:是的,由于 this == o
  • 对称:由于 instanceof 的使用,我们需要查看所有超级和子classes 才能确定
  • 传递性:取决于对称性要求,否则是
  • 一致:是
  • x.equals(null) 应该 return false:是的,由于 instanceof

因此,从纯粹的法律角度来看,这取决于您的继承层次结构中的其他实现是否违反了对称性和传递性 - 请参阅 Any reason to prefer getClass() over instanceof when generating .equals()? 的答案。

但除此之外,鉴于 hashCode 不需要为非等效实例生成不同的值,这通常不是定义相等性的好方法。


一个例子:

具有两个字段 xy

的不可变点 class
class Point {
    final int x;
    final int y

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

-> 有 2^32 * 2^32 = 2^64 个不同的状态,但只有 2^32 个可能的哈希码。这意味着根据 equals.

的实施,有很多点被认为是相等的

另请参阅此示例 equals and hashCode: Is Objects.hash method broken?,了解有人在使用 Objects.hashStrings 创建的哈希发生哈希冲突时绊倒了。