繁体   English   中英

维护特定条件的hashCode契约,equals()取决于两个整数

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

我有一个基本的结构类:

class Employee {
int eId;
String eName;

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

如果满足以下任何条件,则equals()应返回true:

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

我在覆盖equals()没有问题,但是,为了维护哈希代码契约,我也应该覆盖hashCode() 因此,hashCode应该依赖于eIdeName.length() (如果eName s相等,它们的长度也将相等)。 所以有四种情况:

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()应返回e1e2e3的相同值以及e4的不同值。 我无法想出满足这一要求的逻辑。

这是确切的问题:

创建一个类(具有参数名称,id等)。 显示如果将比较此类的2个对象,则它们应在以下任何一种情况下返回true:

A.两者的ID相同。

B.两者的名称相同。

C.两者名称的长度相同。

确保不违反HashCode合同。

你遇到了麻烦,因为你的平等概念是不一致的。 具体来说,它不是传递性的,它是.equals()的合同所要求的。

它是传递性的 :对于任何非空引用值xyz ,如果x.equals(y)返回truey.equals(z)返回true ,则x.equals(z)应返回true

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

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

如果由于某种原因无法使用单独的Comparator ,那么您的Employee对象将基本上不一致,即使您应该实现“可行”的.hashCode() ,也会出现问题。

我想,你不能在你的情况下编写一致的hashCode ,因为你的equals打破了Object.equals方法的契约,即transitivity:

它是传递性的 :对于任何非空引用值xyz ,如果x.equals(y)返回truey.equals(z)返回true ,则x.equals(z)应返回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字段,说明是否应该使用eIdeName 这样您就可以轻松实现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;
    }
}

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

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

或者您可以考虑使用Guava ,它在com.google.common.base.Objects下具有相同的方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM