java HashMap源碼深度解析

 

1、HashMap是什麼

HashMap是基於哈希表的Map接口的實現,提供全部的映射的操做,容許null值和null鍵,存儲的是一個鍵值對對象Entry<K,V>。java

是基於數組+鏈表的結構實現的,在內部維護一個table數組,數組的每一個位置存放一個鏈表的表頭節點,查找元素時,先經過hash算法獲得key的hash值,再經過hash值計算在數組中的索引位置,獲得鏈表的表頭節點,遍歷鏈表獲得value值。算法

2、HashMap類中的主要源碼

一、HashMap中的幾個主要變量

/**
     * 默認的初始化容量,容量必須是2的冪
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * 最大容量
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 默認的負載因子
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * 空表實例
     */
    static final Entry<?,?>[] EMPTY_TABLE = {};

    /**
     * 數組表,長度必須是2的冪
     */
    transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;

    /**
     * map中key-value鍵值對的個數
     */
    transient int size;

    /**
     * 下次擴容的閾值
     */
    int threshold;

    /**
     * 負載因子的值
     */
    final float loadFactor;

    /**
     * Hash表結構性修改次數,用於實現迭代器快速失敗行爲
     */
    transient int modCount;

二、HashMap的初始化方法

/**
     * 主要初始化方法,自定義容量大小、自定義負載因子
     */
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)  //異常處理
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)  
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);  //取初始化大小的最小2的冪
    }

    /**
     * 自定義容量大小、默認負載因子
     */
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    /**
     * 默認容量大小、默認負載因子
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

    /**
     * Constructs a new <tt>HashMap</tt> with the same mappings as the
     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
     * default load factor (0.75) and an initial capacity sufficient to
     * hold the mappings in the specified <tt>Map</tt>.
     *
     * @param   m the map whose mappings are to be placed in this map
     * @throws  NullPointerException if the specified map is null
     */
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

    /**
     * 計算cap的最小2的冪
     * 例如  cap=0001 0101 0111 1111
     * 最小2的冪=0010 0000 0000 0000  即最高位的前一位爲1,低位全是0
     */
    static final int tableSizeFor(int cap) {  //例如  cap=0001 0101 0111 1111
        int n = cap - 1; //處理cap=0001 0000 0000 0000的狀況
        n |= n >>> 1;    //n>>>1=0000 1010 1011 1111, n |= n >>> 1結果=0001 1...   即:最高2位爲1
        n |= n >>> 2;    //最高4位爲1
        n |= n >>> 4;    //最高8位爲1
        n |= n >>> 8;    //最高16位爲1
        n |= n >>> 16;   //最高32位爲1   即:0001 1111 1111 1111
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;  //+1後爲0010 0000 0000 0000
    }

 

/**
     * 用另外一個Map初始化HashMap
     */
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;   //設置默認的負載因子
        putMapEntries(m, false);
    }

    /**
     * Implements Map.putAll and Map constructor
     *
     * @param m the map
     * @param evict false when initially constructing this map, else
     * true (relayed to method afterNodeInsertion).
     */
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // table沒有初始化,則進行初始化
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }else if (s > threshold)
                resize();  //s大於HashMap的下次擴容閾值,則進行擴容

            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { //遍歷入參的Map將節點加入HashMap
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict);
            }
        }
    }

 三、HashMap的put方法

/**
     * 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);  //初始化table
        }
        if (key == null)
            return putForNullKey(value);   //添加key爲空的Entry
        int hash = hash(key);    //計算key的hash值
        int i = indexFor(hash, table.length);   //根據hash值和數組的長度計算在數組中的位置
        for (Entry<K,V> e = table[i]; e != null; e = e.next) { //遍歷鏈表,查詢是否有該key
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  //有,則將value替換爲新值
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;   修改次數加一
        addEntry(hash, key, value, i);   添加entry
        return null;
    }

四、HashMap的get方法

public V get(Object key) {
        if (key == null)
            return getForNullKey();  //key爲null時的處理方法
        Entry<K,V> entry = getEntry(key);  //普通查詢entry的方法

        return null == entry ? null : entry.getValue();
    }


    private V getForNullKey() {
        if (size == 0) {
            return null;
        }
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {  //遍歷table[0]的鏈表,查詢對應entry
            if (e.key == null)
                return e.value;
        }
        return null;
    }


    /**
     * Returns the entry associated with the specified key in the
     * HashMap.  Returns null if the HashMap contains no mapping
     * for the key.
     */
    final Entry<K,V> getEntry(Object key) {
        if (size == 0) {
            return null;
        }

        int hash = (key == null) ? 0 : hash(key);   //計算key的hash值
        for (Entry<K,V> e = table[indexFor(hash, table.length)];   //遍歷對應的鏈表
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))  //判斷key是否相等
                return e;
        }
        return null;
    }
相關文章
相關標籤/搜索