1. 程式人生 > >JDK原始碼 -- Map篇

JDK原始碼 -- Map篇

在java程式語言中,最基本的結構就是兩種,一個是陣列,另外一個是模擬指標(引用),所有的資料結構都可以用這兩個基本結構來構造的,hashmap也不例外。 Hashmap 實際上是一個數組和連結串列的結合體(在資料結構中,一般稱之為“連結串列雜湊“),請看下圖(橫排表示陣列,縱排表示陣列元素【實際上是一個連結串列】)。 

 




HashMap是一個 Entry 鍵值對:

static class Entry<K,V> implements Map.Entry<K,V> {

...

}

先看get() 方法:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        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.equals(k)))
                return e.value;
        }
        return null;
    }

//   首先 根據 key的 hashcode得到hash值(先不糾結演算法),再在 table中 找到該hash地址 對應的值; 如果該地址存在多個值,且以連結串列的形式存在,那麼根據for迴圈,直到取得對應的key的值。


---------------分割線 ---------------


put() 方法:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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;
    }


 void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
            resize(2 * table.length);
    }

解析: 當我們將 新元素 往 map 中加的時候,首先 根據key值得到 hash值; 如果 在該hash值的位置上 已經有值了,那麼將元素以連結串列的形式存放,且最先放進來的元素 放在連結串列的最末尾; 如果 在該hash值的位置上沒有值,直接 將該位置留給 該 K-V鍵值對,         table[bucketIndex] = new Entry<K,V>(hash, key, value, e);


keySet():

返回此對映中包含的鍵的 set 檢視: 內部邏輯 包括迭代和匿名內部類: public Set<K> keySet() {
if (keySet == null) {
   keySet = new AbstractSet<K>() {
public Iterator<K> iterator() {
   return new Iterator<K>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
   return i.hasNext();
}
public K next() {
   return i.next().getKey();
}
public void remove() {
   i.remove();
}
                    };

}
public int size() {
   return AbstractMap.this.size();
}

public boolean contains(Object k) {
   return AbstractMap.this.containsKey(k);
}
   };
}
return keySet;
    }


entrySet() 方法 :

此對映所包含的對映關係的 set 檢視。
用到的 主要邏輯 還是 iterator 。