HashMap实现原理概述

1、数据结构初始化
HashMap是数组与链表两种数据结构的组合,初始化HashMap的时候首先初始化一个数组Entry,该数组中的每个元素是一个静态内部类Entry


 /**
     * An empty table shared by all zero-capacity maps (typically from default
     * constructor). It is never written to, and replaced on first put. Its size
     * is set to half the minimum, so that the first resize will create a
     * minimum-sized table.
     */
    private static final Entry[] EMPTY_TABLE
            = new HashMapEntry[MINIMUM_CAPACITY >>> 1];

/**
     * Constructs a new empty {@code HashMap} instance.
     */
    @SuppressWarnings("unchecked")
    public HashMap() {
        table = (HashMapEntry<K, V>[]) EMPTY_TABLE;
        threshold = -1; // Forces first put invocation to replace EMPTY_TABLE
    }
static class Entry<K,V> implements Map.Entry<K,V> {  
        final K key;  
        V value;  
        final int hash;  
        Entry<K,V> next;  
..........  
} 

2、put方法
HashMap调用put(“key”,”value”)方法的时候,首先根据传入的key计算出相对应的hash值,再将得到的hash值与(数组长度-1)进行&运算,得到这个key对应的Entry元素在数组中下标。如果该下标处已经有元素存在,判断该元素与已经存在的元素的key值是否相同。如果相同,就将该处key所对应的value值替换,key不变;如果key不相同,但是key对应的hash值相同,那么在数组中同一位置上的元素将以链表的形式存储,最先进入该位置的放到链表的尾部,新加入的放到链表的头部。


/**
     * Maps the specified key to the specified value.
     *
     * @param key
     *            the key.
     * @param value
     *            the value.
     * @return the value of any previous mapping with the specified key or
     *         {@code null} if there was no such mapping.
     */
    @Override public V put(K key, V value) {
        if (key == null) {
            return putValueForNullKey(value);
        }

        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        int index = hash & (tab.length - 1);
        for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
            if (e.hash == hash && key.equals(e.key)) {
                preModify(e);
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }

        // No entry for (non-null) key is present; create one
        modCount++;
        if (size++ > threshold) {
            tab = doubleCapacity();
            index = hash & (tab.length - 1);
        }
        addNewEntry(key, value, hash, index);
        return null;
    }

3、get()方法
HashMap调用get(“key”)方法的时候,同样首先计算出key所对应的hash值,根据hash值找到key对应的Entry元素在数组中的位置,然后通过key的equals方法,在该位置处找到相应的元素。


/**
     * Returns the value of the mapping with the specified key.
     *
     * @param key
     *            the key.
     * @return the value of the mapping with the specified key, or {@code null}
     *         if no mapping for the specified key is found.
     */
    public V get(Object key) {
        if (key == null) {
            HashMapEntry<K, V> e = entryForNullKey;
            return e == null ? null : e.value;
        }

        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
                e != null; e = e.next) {
            K eKey = e.key;
            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
                return e.value;
            }
        }
        return null;
    }

4、HashMap扩容
HashMap初始化时默认的capaticy为16,loadFactor为0.75,当HashMap的容量大于16*0.75=12的时候,HashMap需要进行数组扩容,数组大小变为16*2=32,即扩展为原来的一倍。然而当数组长度发生变化时,HashMap中的各个元素的位置也会发生变化,原因是,元素位置是根据key对应的hash值与数组长度-1进行&操作得到的,扩容后,数组长度发生改变,则需要重新计算每一个元素在数组中的位置,这是一个非常耗时的操作,所以如果我们预先知道HashMap中元素的个数,通过改变capacity或loadFactory(一般不改变这个值)来避免HashMap出现扩容,以提高HashMap的工作效率。如:已知元素有60个,为了避免扩容,让capacity*0.75>60,且capacity为2的n次方,则capacity应该取
128更合适,即new HashMap(128);


/**
     * Constructs a new {@code HashMap} instance with the specified capacity and
     * load factor.
     *
     * @param capacity
     *            the initial capacity of this hash map.
     * @param loadFactor
     *            the initial load factor.
     * @throws IllegalArgumentException
     *                when the capacity is less than zero or the load factor is
     *                less or equal to zero or NaN.
     */
    public HashMap(int capacity, float loadFactor) {
        this(capacity);

        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
            throw new IllegalArgumentException("Load factor: " + loadFactor);
        }

        /*
         * Note that this implementation ignores loadFactor; it always uses
         * a load factor of 3/4. This simplifies the code and generally
         * improves performance.
         */
    }

总结:本文主要讲了HashMap的数据存储结构、put、get方法、以及HashMap扩容的一些基本原理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值