Item 9: Always override hashCode when you override equals

1.  You must override hashCode in every class that overrides equals. Failure to do so will result in a violation of the general contract for Object.hashCode, which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

2.  The contract for Object.hashCode:
    a)  Whenever it is invoked on the same object more than once during an execution of an application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified.
    b)  If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
    c)  It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However producing distinct integer results for unequal objects may improve the performance of hash tables.

3.  Even if the two instances happen to hash to the same bucket, the get method will almost certainly return null, as HashMap has an optimization that caches the hash code associated with each entry and doesn’t bother checking for object equality if the hash codes don’t match.

4.   Ideally, a hash function should distribute any reasonable collection of unequal instances uniformly across all possible hash values. Here is a simple recipe:
    a)  Store some constant nonzero value, say, 17, in an int variable called result.
    b)  For each significant field f in your object (each field taken into account by the equals method, that is), do the following:
        1)  Compute an int hash code c for the field:
            i)  If the field is a boolean, compute (f ? 1 : 0).
            ii)  If the field is a byte, char, short, or int, compute (int) f.
            iii)  If the field is a long, compute (int) (f ^ (f >>> 32)).
            iv)  If the field is a float, compute Float.floatToIntBits(f).
            v)  If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in iii)
            vi)  If the field is an object reference and this class’s equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. If a more complex comparison is required, compute a “canonical representation” for this field and invoke hashCode on the canonical representation. If the value of the field is null, return 0.
            vii)  If the field is an array, treat it as if each element were a separate field. If every element in an array field is significant, you can use one of the Arrays.hashCode methods.
        2)  Combine the hash code c computed in step 1) into result as follows:
                result = 31 * result + c;
    b)      Return result.

5.  You must exclude any fields that are not used in equals comparisons, or you risk violating the second provision of the hashCode contract. A nonzero initial value is used in step a) so the hash value will be affected by initial fields whose hash value, as computed in step 1), is zero. If zero were used as the initial value in step 1, the overall hash value would be unaffected by any such initial fields, which could increase collisions. The value 17 is arbitrary.

6.  A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31 * i == (i << 5) - i. Modern VMs do this sort of optimization automatically.

7.  If a class is immutable and the cost of computing the hash code is significant, you might consider caching the hash code in the object rather than recalculating it each time it is requested. If you believe that most objects of this type will be used as hash keys, then you should calculate the hash code when the instance is created. Otherwise, you might choose to lazily initialize it the first time hashCode is invoked.

你可能感兴趣的:(HashMap,equals,HashCode,hashset,Hashtable)