开发者

Java: Use hashCode() inside of equals() for convenience?

Consider the following test case, is it a bad practice to use the hashCode method inside of equals as a convenient shortcut?

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;
    }   
}

Output from main method:

1097562307
1097562307
t1.equals(t2) ? true


In general, it's not at all safe to compare the hashCode instead of using equals. When equals returns false, hashCode may return the same value, per the contract of hashCode.


Very bad! HashCode equality does not mean that equals returns true. The contract is that two objects that are equal must have the same hashCode. But it DOES NOT state the two objects with the same HashCode must be equal.


As all other answers state this is bad practice. However, one situation where you might want to refer to the hash code within the equals method is in cases where you have an immutable object and have cached the hash code previously. This allows you to perform a cheap inexact comparison before performing a full comparison. For example:

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;
    }
}


This is not OK. Hashcodes, by their very nature, are not guaranteed to be unique.


Bad practice? More than that, it's completely wrong. Two un-equal objects can return the same hash code. Do not do this.


Here is the contract, copied from the Object specification [JavaSE6]:

It is not required that if two objects are unequal according to the equals(Ob- ject) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

To answer your question, No. Not a good idea.


As Ryan Stewart says, your code as written is faulty.

A situation in which it might be useful to use the hash-code of your objects in equals() is when your object caches the hash codes, and determining equality is portentially expensive. In that case you might use equality of the cached hash codes as one of the early necesssary-but-not-sufficient checks for equality, to return false fast for most pairs of objects that are not equals().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜