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

时间:2015-05-14 05:16:09

标签: java equals hashcode

我有一个基本类,结构如下:

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的长度相同。
  4. 我在覆盖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:

         

    一个。两者的ID都相同。

         

    B中。两者的名称相同。

         

    ℃。两者的名称长度相同。

         

    确保不违反HashCode合同。

3 个答案:

答案 0 :(得分:7)

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

  

transitive :对于任何非空引用值xyz,如果x.equals(y)返回{{1} }和true返回y.equals(z),然后true应该返回x.equals(z)

根据您的定义,true等于e1e2,但e3不等于e2。这与Java的平等概念不相容。这也是您在定义合理e3实施时遇到麻烦的原因。

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

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

答案 1 :(得分:4)

我想,你不能在你的案例中写出一致的DataContext,因为你的hashCode违反了Object.equals方法的合同,即及物性:

  

transitive :对于任何非空引用值equalsxy,如果z返回{{1} }和x.equals(y)会返回true,然后y.equals(z)应该返回true

假设您有以下代码:

x.equals(z)

在这种情况下,您的等号操作trueEmployee 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)已定义equalsEmployee,因此最好添加一个eId字段,说明eName还是boolean应该使用。这样,您就可以轻松实现eIdeName。这样实现可能是这样的(假设为了简单起见equals不能是hashCode):

eName

答案 2 :(得分:0)

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

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

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

下有相同的方法