HashTable原理解析

来源:互联网 发布:淘宝店铺布局和理性 编辑:程序博客网 时间:2024/06/05 02:24

    When I use an object as a key in a Hashtable, what in the Object class must I override and why?

    Whenyou create your own key object for use in a Hashtable,you must override the Object.equals() and Object.hashCode() methodssince Hashtable usesa combination of the key's hashCode() andequals() methodsto store and retrieve its entries quickly. It's also a general rule that whenyou override equals(),you always override hashCode().

Moreon why

    A slightly more in-depth explanation will help you understandHashtable'smechanism for storage and retrieval. A Hashtable internallycontains buckets in which it stores the key/value pairs. The Hashtableusesthe key's hashcode to determine to which bucket the key/value pair should map

 

图片

Figure 1. AHashtable and its buckets

    Figure1 shows a Hashtable andits buckets. When you pass a key/value to the Hashtable,it queries the key's hashcode. TheHashtable usesthat code to determine the bucket in which to place the key/value. So, forexample, if the hashcode equals zero, theHashtable placesthe value into Bucket 0. Likewise, if the hashcode is two, the Hashtable placesthe value into Bucket 2. (This is a simplistic example; the Hashtable willmassage the hashcode first so theHashtable doesn'ttry to insert the value outside the bucket.)

By using the hashcode this way, the Hashtable canalso quickly determine in which bucket it has placed the value when you try toretrieve it.

Hashcodes, however, represent only half the picture. The hashcodeonly tells the Hashtable intowhich bucket to drop the key/value. Sometimes, however, multiple objects maymap to the same bucket, an event known as a collision. In Java, the Hashtable respondsto a collision by placing multiple values into the same bucket (otherimplementations may handle collisions differently). Figure 2 shows what a Hashtable mightlook like after a few collisions.

 


图片

Figure 2. AHashtable after a few collisions

Nowimagine that you call get() witha key that maps to Bucket 0. The Hashtable willnow need to peform a sequential search through the key/value pairs in Bucket 0to find your requested value. To perform this lookup, the Hashtable executesthe following steps:

1.    Query the key's hashcode

2.    Retrieve the list of key/valuesresiding in the bucket given by the hashcode

3.    Scan through each entrysequentially until a key that equals the key passed into get() isfound

Along answer to a short question I know, but it gets worse. Properly overriding equals() and hashCode() isa nontrivial exercise. You must take extreme care to guarantee both methods'contracts.

On implementing equals()

According to the equals() Javadoc,the method must conform to the following rules:

"The equals() method implements an equivalence relation:

·        It is reflexive: For anyreference value x, x.equals(x) shouldreturn true

·        It is symmetric: For anyreference values x and y, x.equals(y) shouldreturn true if and only if y.equals(x) returnstrue

·        It is transitive: For anyreference values x, y, and z, if x.equals(y) returnstrue and y.equals(z) returnstrue, then x.equals(z) shouldreturn true

·        It is consistent: For anyreference values x and y, multiple invocations of x.equals(y) consistentlyreturn true or consistently return false, provided no information used inequals comparisons on the object is modified

·        For any non-null reference valuex, x.equals(null) shouldreturn false

In Effective Java, JoshuaBloch offers a five-step recipe for writing an effective equals() method. Here's the recipe in code form:

publicclass EffectiveEquals {

    private int valueA;

    private int valueB;

    . . .

    public boolean equals( Object o ) {

        if(this == o) {  // Step 1: Perform an == test

            return true;

        }

        if(!(o instanceof EffectiveEquals)){  // Step

2:Instance of check

            return false;

        }

        EffectiveEquals ee = (EffectiveEquals) o;//

Step3: Cast argument

        // Step 4: For each important field,check to

see ifthey are equal

        // For primitives use ==

        // For objects use equals() but be sureto also

        // handle the null case first

        return ee.valueA == valueA &&

               ee.valueB == valueB;

    }

    . . .

}


Note: Youneed not perform a null check since null instanceof EffectiveEquals willevaluate to false.

Finally, for Step 5, go back to equals()'scontract and ask yourself if the equals() methodis reflexive, symmetric, and transitive. If not, fix it!

On implementing hashCode()

For hashCode()'sgeneral contract, the Javadoc says:

·        "Whenever it is invoked onthe same object more than once during an execution of a Java application, the hashCode() methodmust consistently return the same integer, provided no information used inequals comparisons on the object is modified. This integer need not remainconsistent from one execution of an application to another execution of thesame application.

·        If two objects are equalaccording to the equals(Object) method,then calling the hashCode() methodon each of the two objects must produce the same integer result.

·        It is not required that if twoobjects are unequal according to theequals(java.lang.Object method,then calling the hashCode() methodon each of the two objects must produce distinct integer results. However, theprogrammer should be aware that producing distinct integer results for unequalobjects may improve the performance of hashtables."

Creatinga properly working hashCode() methodproves difficult; it becomes even more difficult if the object in question isnot immutable. You can calculate a hashcode for a given object in many ways.The most effective method bases the number upon the object's fields. Moreover,you can combine these values in various ways. Here are two popular approaches:

·        You can turn the object's fieldsinto a string, concatenate the strings, and return the resulting hashcode

·        You can add each field's hashcodeand return the result


0 0
原创粉丝点击