这是否合法?

时间:2017-03-09 08:09:44

标签: java equals

我遇到过这段代码。我从未见过以这种方式实现的平等。让我感到震惊的是,它真的是“整洁”,从某种意义上来说只需要一行样板。

然而,我之前从未见过这种方法的事实让我怀疑。根据Java equals和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);
}

4 个答案:

答案 0 :(得分:5)

您可以根据哪个类的两个实例彼此相等来定义条件。

但是,您应该考虑pageTrackingRequestsearchId&的不同组合。 productId属性可能会产生相同的哈希码,您可能不希望将这些不同的组合视为彼此相等。 equals要求所有3个属性分别相等,这可能更有意义。

答案 1 :(得分:1)

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

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

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

equals方法会开始返回true所有不应该出现的对象。

答案 2 :(得分:1)

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

至于“合法”方面,Contract of Object.equals

  

equals方法在非null对象引用上实现等价关系:

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

一步一步:

  • 反身:是的,由于this == o
  • 对称:由于使用instanceof,我们需要查看所有超级和子类以确保
  • 传递:取决于对称要求,否则是
  • 一致:是
  • x.equals(null)应该返回false:是的,由于instanceof

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

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

一个例子:

包含两个字段xy

的不可变点类
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.hash Strings创建的哈希的哈希冲突的人。

答案 3 :(得分:0)

这种做法是错误的。散列码相等不是决定性因素,因为不相等的对象可能具有相同的散列。它是一个设计好的bug。