为特定条件维护 hashCode 合同,equals() 取决于两个整数

Maintaining hashCode contract for the specific condition, equals() depending on two integers

我有一个基本的 class 结构:

class Employee {
int eId;
String eName;

Employee(int id, String name) {
    this.eId= id;
    this.eName= name;
}

相等的条件是 equals() 应该 return 为真,如果 任何 为真:

  1. eId相同
  2. eName相同
  3. eName 的长度相同。

我在覆盖 equals() 时没有问题,但是,为了维护哈希码合同,我也应该覆盖 hashCode()。因此,hashCode 应该取决于 eIdeName.length()(如果 eName 相等,则它们的长度也相等)。所以有四种情况:

Employee e1 = new Employee(4, "John");
Employee e2 = new Employee(3, "Jane");
Employee e3 = new Employee(4, "Jim");
Employee e4 = new Employee(7, "Random");

hashCode() 应 return e1e2e3 的相同值以及 e4 的不同值。我想不出满足这个要求的逻辑。

这是确切的问题:

Create a class (having parameters name, id etc). Show that if 2 objects of this class will be compared then they should return true in any of below case :

A. Id of both are same.

B. Name of both are same.

C. Length of name’s of both are same.

Make sure HashCode contract should not violate.

如果你使用Java 7,那么我认为使用java.util.Objects很容易:

@Override
public int hashCode() {
    return Objects.hash(eld,eName.length());
}

或者你可以考虑Guava,在com.google.common.base.Objects

下也有同样的方法

您 运行 遇到了麻烦,因为您的平等观念不一致。具体来说,它不是可传递的,.equals() 的合同要求。

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.

根据您的定义,e1 等于 e2e3,但 e2 不等于 e3。这与 Java 的平等概念不相容。这也是为什么您 运行 在定义合理的 .hashCode() 实现时遇到麻烦。

然而,如果您使用的是 Guava,您可以定义自定义 Comparator (or Ordering。对于大多数用例(如排序、搜索或过滤),您应该能够像使用 .equals() 方法一样使用单独的 Comparator 实例。您实际上是在尝试定义 等效 对象,而不是 相等 对象。

如果您出于任何原因不能使用单独的 Comparator,您的 Employee 对象将根本不一致,即使您应该得到 "workable" .hashCode() 实施。

我想,你不能在你的情况下写一个一致的 hashCode,因为你的 equals 违反了 Object.equals 方法的契约,即传递性:

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.

假设你有这个代码:

Employee a = new Employee(1, "John");
Employee b = new Employee(1, "James");
Employee c = new Employee(2, "James");

在这种情况下,您的等于运算 a.equals(b)b.equals(c),而不是 a.equals(c)

我建议重新考虑 equals 的实施。可能您的 Employee 定义了 eIdeName,因此最好添加一个 boolean 字段来说明是 eId 还是 eName应该使用。这样你就可以轻松实现equalshashCode。这样的实现可能是这样的(为简单起见,假设 eName 不能是 null):

class Employee {
    boolean useName;
    int eId = 0;
    String eName;

    Employee(int id) {
        this.eId = id;
        this.useName = false;
    }

    Employee(String name) {
        this.eName = name;
        this.useName = true;
    }

    @Override
    public int hashCode() {
        return useName ? eName.length() * 1337 : eId * 7331;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (useName != other.useName)
            return false;
        if (useName) {
            if (eName.length() != other.eName.length())
                return false;
        } else {
            if (eId != other.eId)
                return false;
        }
        return true;
    }
}