HashMap底层原理

来源:互联网 发布:benq显示器怎么样 知乎 编辑:程序博客网 时间:2024/05/20 07:19

首先简单说说HashMap和HashTable的区别

  • 最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合;
  • HashMap可以使用null作为key,而Hashtable则不允许null作为key;
  • HashMap的初始容量为16,Hashtable初始容量为11;
  • HashMap是对Map接口的实现,HashTable实现了Map接口和Dictionary抽象类;
  • 两者计算hash的方法不同,Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模,HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸;
  • HashMap和Hashtable的底层实现都是数组+链表结构实现。

    接下来简要分析HashMap和HashTable的底层实现原理:

    HashMap的创建初始过程
    默认填充因子

HashMap的put方法

首先看接口的put方法定义

    /**     * Associates the specified value with the specified key in this map     * (optional operation).  If the map previously contained a mapping for     * the key, the old value is replaced by the specified value.  (A map     * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only     * if {@link #containsKey(Object) m.containsKey(k)} would return     * <tt>true</tt>.)     *     * @param key key with which the specified value is to be associated     * @param value value to be associated with the specified key     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with <tt>key</tt>,     *         if the implementation supports <tt>null</tt> values.)     * @throws UnsupportedOperationException if the <tt>put</tt> operation     *         is not supported by this map     * @throws ClassCastException if the class of the specified key or value     *         prevents it from being stored in this map     * @throws NullPointerException if the specified key or value is null     *         and this map does not permit null keys or values     * @throws IllegalArgumentException if some property of the specified key     *         or value prevents it from being stored in this map     */    V put(K key, V value);

HashMap会对null值key进行特殊处理,总是放到table[0]位置
put过程是先计算hash然后通过hash与table.length取摸计算index值,然后将key放到table[index]位置,当table[index]已存在其它元素时,会在table[index]位置形成一个链表,将新添加的元素放在table[index],原来的元素通过Entry的next进行链接,这样以链表形式解决hash冲突问题,当元素数量达到临界值(capactiy*factor)时,则进行扩容,是table数组长度变为table.length*2

再看HashMapput()方法的源码

    /**     * 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.     *     * @param key key with which the specified value is to be associated     * @param value value to be associated with the specified key     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with <tt>key</tt>.)     */    public V put(K key, V value) {        if (table == EMPTY_TABLE) {            inflateTable(threshold);        }        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;    }

再看HashMap的get()方法
get方法
同样当key为null时会进行特殊处理,在table[0]的链表上查找key为null的元素
get的过程是先计算hash然后通过hash与table.length取摸计算index值,然后遍历table[index]上的链表,直到找到key,然后返回

    /**     * Returns the value to which the specified key is mapped,     * or {@code null} if this map contains no mapping for the key.     *     * <p>More formally, if this map contains a mapping from a key     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :     * key.equals(k))}, then this method returns {@code v}; otherwise     * it returns {@code null}.  (There can be at most one such mapping.)     *     * <p>A return value of {@code null} does not <i>necessarily</i>     * indicate that the map contains no mapping for the key; it's also     * possible that the map explicitly maps the key to {@code null}.     * The {@link #containsKey containsKey} operation may be used to     * distinguish these two cases.     *     * @see #put(Object, Object)     */    public V get(Object key) {        if (key == null)            return getForNullKey();        Entry<K,V> entry = getEntry(key);        return null == entry ? null : entry.getValue();    }

最后看remove()方法
remove方法和put get类似,计算hash,计算index,然后遍历查找,将找到的元素从table[index]链表移除

    /**     * Removes the mapping for the specified key from this map if present.     *     * @param  key key whose mapping is to be removed from the map     * @return the previous value associated with <tt>key</tt>, or     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.     *         (A <tt>null</tt> return can also indicate that the map     *         previously associated <tt>null</tt> with <tt>key</tt>.)     */    public V remove(Object key) {        Entry<K,V> e = removeEntryForKey(key);        return (e == null ? null : e.value);    }
0 0
原创粉丝点击