Java:为方便起见,在equals()中使用hashCode()?

时间:2011-09-14 14:05:02

标签: java equals hashcode

考虑以下测试用例,将equals中的hashCode()方法用作方便的快捷方式是不好的做法吗?

public class Test 
{    
    public static void main(String[] args){
        Test t1 = new Test(1, 2.0, 3, new Integer(4));
        Test t2 = new Test(1, 2.0, 3, new Integer(4));
        System.out.println(t1.hashCode() + "\r\n"+t2.hashCode());
        System.out.println("t1.equals(t2) ? "+ t1.equals(t2));
    }

    private int myInt;
    private double myDouble;
    private long myLong;
    private Integer myIntObj;

    public Test(int i, double d, long l, Integer intObj ){
        this.myInt = i;
        this.myDouble = d;
        this.myLong = l;
        this.myIntObj = intObj;
    }

    @Override
    public boolean equals(Object other)
    {        
        if(other == null) return false;
        if (getClass() != other.getClass()) return false;            

        return this.hashCode() == ((Test)other).hashCode();//Convenient shortcut?
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 53 * hash + this.myInt;
        hash = 53 * hash + (int) (Double.doubleToLongBits(this.myDouble) ^ (Double.doubleToLongBits(this.myDouble) >>> 32));
        hash = 53 * hash + (int) (this.myLong ^ (this.myLong >>> 32));
        hash = 53 * hash + (this.myIntObj != null ? this.myIntObj.hashCode() : 0);
        return hash;
    }   
}

主要方法的输出:

1097562307
1097562307
t1.equals(t2) ? true

7 个答案:

答案 0 :(得分:41)

通常,比较hashCode()而不是使用equals()并不安全。当equals()返回false时,hashCode()可能按照contract of hashCode()返回相同的值。

答案 1 :(得分:16)

非常糟糕! HashCode相等并不意味着equals返回true。合同是两个相等的对象必须具有相同的hashCode。但它没有说明具有相同HashCode的两个对象必须相等。

答案 2 :(得分:7)

正如所有其他答案所述,这是不好的做法。 但是,您可能希望在equals方法中引用哈希代码的一种情况是,您有一个不可变对象并且之前已经缓存了哈希码。这允许您在执行完整比较之前执行廉价的不精确比较。例如:

public class MyImmutable {
    private final String a;
    private final String b;
    private final int c;

    private int hashCode;

    public MyImmutable(String a, String b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        MyImmutable that = (MyImmutable) o;

        // Compare cached hashCodes first before performing more expensive comparison.
        return hashCode == that.hashCode() && c == that.c && !(a != null ? !a.equals(that.a) : that.a != null) && !(b != null ? !b.equals(that.b) : that.b != null);
    }

    @Override
    public int hashCode() {
        if (hashCode == 0) {
            // hashCode not cached, or it was computed as 0 (we recalculate it in this case).
            hashCode = a != null ? a.hashCode() : 0;
            hashCode = 31 * hashCode + (b != null ? b.hashCode() : 0);
            hashCode = 31 * hashCode + c;
        }

        return hashCode;
    }
}

答案 3 :(得分:6)

确定。从本质上讲,哈希德斯不保证是独一无二的。

答案 4 :(得分:5)

糟糕的做法?更重要的是,这是完全错误的。两个不相等的对象可以返回相同的哈希码。不要这样做。

答案 5 :(得分:3)

这是从对象规范[JavaSE6]:

复制的合同
  

如果两个对象根据不相等而不是必需的   equals(对象)方法,然后在每个上调用hashCode方法   这两个对象必须产生不同的整数结果。然而   程序员应该意识到产生不同的整数结果   对于不对等的对象可能会提高哈希表的性能。

要回答你的问题,不是。不是一个好主意。

答案 6 :(得分:3)

正如Ryan Stewart所说,您编写的代码有问题。

equals()中使用对象的哈希码可能有用的情况是,当您的对象缓存哈希码时,确定相等性是非常昂贵的。在这种情况下,您可以使用缓存哈希码的相等性作为早期必需但不充分的相等性检查之一,对于大多数非false对象,快速返回equals()