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

bra*_*ido 18 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;
    }   
}
Run Code Online (Sandbox Code Playgroud)

主方法输出:

1097562307
1097562307
t1.equals(t2) ? true
Run Code Online (Sandbox Code Playgroud)

Rya*_*art 42

通常,比较hashCode()而不是使用equals()并不安全.当equals()返回false时,hashCode()可以根据hashCode()约定返回相同的值.


Joh*_*n B 16

很坏!HashCode相等并不意味着equals返回true.合同是两个相等的对象必须具有相同的hashCode.但它没有说明具有相同HashCode的两个对象必须相等.


Ada*_*ski 9

正如所有其他答案所述,这是不好的做法. 但是,您可能希望在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Paul:实际上"that"只会在需要时计算其哈希码,因为hashCode()实现将计算并缓存哈希码.你也没有保证也是正确的.但是,该解决方案针对的情况是您可能会多次与相同的不可变对象进行比较(例如,如果将它们存储在HashMap中).在这种情况下,基于int的哈希码比较提供了效率增益. (2认同)

Ern*_*ill 6

不行.从本质上讲,哈希德斯不保证是独一无二的.


Sea*_*wen 5

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