Map的實現類Hashtable各種方法源碼解析

  1. map.put 方法解析

    // map.put 方法 不能存null的key和value 
    // 不成立:map.put(null, null) map.put(null,Object) map.put(Object, null) 
    // map.put 在這裏沒有如果put不滿足的數值 會拋出異常 java.lang.NullPointerException
    public synchronized V put(K key, V value) {
            // Make sure the value is not null
            if (value == null) {// key也不能爲null 可以爲字符串: "",字符串""的 hash 爲0
                throw new NullPointerException();
            }
    
            // Makes sure the key is not already in the hashtable.
            Entry<?,?> tab[] = table;//定義tab[]
            int hash = key.hashCode();//取key的hash值
            int index = (hash & 0x7FFFFFFF) % tab.length;//取模運算 計算需要存儲的位置
            @SuppressWarnings("unchecked")
            Entry<K,V> entry = (Entry<K,V>)tab[index];
            //確定當前位置是否已存在數據,hash存儲會有數據碰撞的機率,這就是爲什麼說兩個對象的        
            // hashcode相等,值卻不一定相等的原因,例如: Aa 和 BB 的hashCode 都是2112 
            //循環判斷當前需要存儲的位置的entry是否爲已存儲的數據,hash表存儲數據格式(數組與鏈表存儲    
            //的結合) 成立則覆蓋oldValue並返回old 不成立則繼續循環下一個
            for(; entry != null ; entry = entry.next) {
                // 判斷是否是重複key數據put
                if ((entry.hash == hash) && entry.key.equals(key)) {
                    V old = entry.value;
                    entry.value = value;
                    return old;
                }
            }
    
            addEntry(hash, key, value, index);//執行newEntry的add操作
            return null;
        }
        
        // addEntry方法解析 執行數組的擴容操作以及add操作
        private void addEntry(int hash, K key, V value, int index) {
            modCount++;
    
            Entry<?,?> tab[] = table;//定義tab[]
            //判斷當前的存儲數量是否超出或等於當前數組最大的容量閥值
            if (count >= threshold) {
                // Rehash the table if the threshold is exceeded
                rehash();//執行擴容的方法 oldCP * 2 + 1
    
                tab = table;//擴容之後的newTable
                hash = key.hashCode();
                index = (hash & 0x7FFFFFFF) % tab.length;//取模計算需要存放的位置
            }
    
            // Creates the new entry.
            @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>) tab[index];// 取當前位置是否存在oldEntry
            //執行Entry的鏈表存儲結構先入的放到後面
            //protected Entry(int hash, K key, V value, Entry<K,V> next) {
                //this.hash = hash;
                //this.key =  key;
                //this.value = value;
                //this.next = next;
            //}
            tab[index] = new Entry<>(hash, key, value, e);
            count++;
        }
        
        // rehash() 方法 執行數組的擴容方法 oldCp * 2 + 1
        @SuppressWarnings("unchecked")
        protected void rehash() {
            int oldCapacity = table.length;//定義oldCp
            Entry<?,?>[] oldMap = table;// 定義 oldMap 執行copy時使用 執行擴容之後的數組爲table
    
            // overflow-conscious code
            int newCapacity = (oldCapacity << 1) + 1;// newCp 爲 oldCp * 2 + 1
            if (newCapacity - MAX_ARRAY_SIZE > 0) {// HashTable 的最大容量是MAX_ARRAY_SIZE
                if (oldCapacity == MAX_ARRAY_SIZE)
                    // Keep running with MAX_ARRAY_SIZE buckets
                    return;
                newCapacity = MAX_ARRAY_SIZE;// 定義newCp 爲MAX_ARRAY_SIZE
            }
            Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
    
            modCount++;
            // 最大容量閥值爲 newCp * 0.75(默認) 或者 MAX_ARRAY_SIZE + 1 
            threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
            table = newMap;// 從新定義table 執行copy操作
    
            for (int i = oldCapacity ; i-- > 0 ;) {// 循環執行數據的copy
                // 執行 散列表數據結構的 copy 
                for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                    Entry<K,V> e = old;// 將oldEntry 賦值 給e
                    old = old.next;// 從新定義oldEntry 爲old.next
                    
                    int index = (e.hash & 0x7FFFFFFF) % newCapacity;// 取模計算新數組的存放位置
                    e.next = (Entry<K,V>)newMap[index];//防止數據丟失 鏈表存儲結構 先入後出 
                    newMap[index] = e;// 執行數據的存放
                }
            }
        }

     

  2. map.get(key) 方法解析

        // map.get() 方法源碼解析
        @SuppressWarnings("unchecked")
        public synchronized V get(Object key) {
            Entry<?,?> tab[] = table;// 定義tab[]
            int hash = key.hashCode();//取key的hashCode
            int index = (hash & 0x7FFFFFFF) % tab.length;//與運算 取模計算存儲的位置
            for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {// 循環對比取值
                if ((e.hash == hash) && e.key.equals(key)) {// 判斷是否匹配
                    return (V)e.value;//成功返回value
                }
            }
            return null;//無匹配數據返回null
        }

     

  3. map.putAll(Map<? extends K, ? extends V> m)  方法解析

        // map.putAll() 方法源碼解析
        // 循環執行map數據的put操作 
        public synchronized void putAll(Map<? extends K, ? extends V> t) {
            for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
                put(e.getKey(), e.getValue());// put源碼
        }

     

  4. map.remove(key) 方法解析

        // map.remove(Object key) 方法源碼解析
        // remove 的方法 是先執行get(key) 方法 在執行數據的remove
        public synchronized V remove(Object key) {
            Entry<?,?> tab[] = table;//定義tab[]
            int hash = key.hashCode();//去key的hashCode
            int index = (hash & 0x7FFFFFFF) % tab.length;//與運算 取模 計算數據的存儲位置
            @SuppressWarnings("unchecked")
            Entry<K,V> e = (Entry<K,V>)tab[index];// 找到需要remove的鏈表數據結構對象
            //循環對比 找到需要remove的對象
            for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {//判斷條件是否成立
                    modCount++;
                    if (prev != null) {//如果prev != null 鏈表數據結構remove 只需要移動指針操作
                        prev.next = e.next;
                    } else {
                        tab[index] = e.next;//當前鏈表的first位置,移動指針操作
                    }
                    count--;
                    V oldValue = e.value;
                    e.value = null;// 設置爲null 方便回收
                    return oldValue;//返回remove的value值
                }
            }
            return null;// 不匹配返回null
        }

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章