简体   繁体   中英

About the HashMap, rehashing

Directly from this javadoc:

An instance of HashMap has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.

Let's say that the number of entries in the hash table exceeds the product of the load factor and the current capacity... the data structure gets rehashed and the number of buckets will be approximately twice as much.. ok... If the hashcode() method remains the same... how can increasing the number of buckets diminish the lookup waiting time? If the hashcode is the same the lookup will be done in the same bucket even though there is another empty bucket newly created next to it.. isn't it? (sure it's not it but why?) Thanks in advance.

While the hashCode() return values will stay the same, those values aren't directly used to find a bucket. They are transformed into an index into the buckets array, usually by index = hashCode() % tableSize . Consider a table of size 10 with two keys that have hash values 5 and 15. At table size 10, they end up in the same bucket. Resize the table to 20, and they end up in distinct buckets.

It is a simplified version but imagine that you find the bucket with:

int bucket = hash % 8; //8 buckets

After rehashing it will become:

int bucket = hash % 16;//16 buckets

If your initial hash was 15, before rehashing it was in bucket 7 but after rehashing it is in bucket 15.

The question has already been answered correctly. For deeper understanding, here are the relevant code parts from java.util.HashMap .

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{

    static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;

        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

        ... methods...
    }


    /**
     * The table, resized as necessary. Length MUST Always be a power of two.
     */
    transient Entry<K,V>[] table;


    /**
     * Returns index for hash code h.
     */
    static int indexFor(int h, int length) {
        return h & (length-1);
    }


    /**
     * Adds a new entry with the specified key, value and hash code to
     * the specified bucket.  It is the responsibility of this
     * method to resize the table if appropriate.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }


    /**
     * Like addEntry except that this version is used when creating entries
     * as part of Map construction or "pseudo-construction" (cloning,
     * deserialization).  This version needn't worry about resizing the table.
     */
    void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
// *** you see how the next line builds a linked list of entries with the same hash code ***
        table[bucketIndex] = new Entry<>(hash, key, value, e);
        size++;
    }



    /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     */
    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }



}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM