1. 程式人生 > >Java集合類原始碼解析:AbstractMap

Java集合類原始碼解析:AbstractMap

目錄

引言

今天學習一個Java集合的一個抽象類 AbstractMap ,AbstractMap 是Map介面的 實現類之一,也是HashMap、TreeMap、ConcurrentHashMap 等的父類,它提供了Map 介面中方法的基本實現(關於Map介面有疑惑的同學可參考 Java集合類根介面:Collection 和 Map

原始碼解析

因為 AbstractMap 類是實現Map介面的抽象類,所以其內部也包含了操作子元素的實體介面 Entry

,其原始碼方法對元素的操作都是基於 Entry 的檢視實現的。

抽象函式entrySet()

AbstractMap類中有一個唯一的抽象函式 entrySet() ,類中對集合檢視操作的很多方法都是依賴這個抽象函式的,它返回一個儲存所有 key-value 對映的Set。

當我們要實現一個不可變的 Map 時,只需要繼承 AbstractMap 類並實現 entrySet() 即可。

如果想要實現一個可變的 Map ,我們還需要重寫 put() 方法,因為 AbstractMap 類中預設不支援 put實現,子類必須重寫該方法的實現,否則會丟擲異常:

public V put(K key, V value) {
    throw new UnsupportedOperationException();
}

在這裡,有人會疑惑為什麼必須重寫 put 方法呢,很大可能是官方考慮到也許會有不可修改的Map實現子類繼承 AbstractMap,如果 put 方法預設可以操作,那不可修改的子類就行不通了。

兩個集合檢視

AbstractMap沒有提供 entrySet() 的實現,但是卻提供了 keySet() 與 values() 集合檢視的預設實現,它們都是依賴於 entrySet() 返回的集合檢視實現的,這是他們的原始碼:

  • keySet()
// 返回一個AbstractSet的實現,包含了所有的key
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 isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object k) {
                return AbstractMap.this.containsKey(k);
            }
        };
    }
    return keySet;
}
  • values()
// 返回一個AbstractCollection的實現,包含了所有的value
public Collection<V> values() {
    if (values == null) {
        values = new AbstractCollection<V>() {
            public Iterator<V> iterator() {
                return new Iterator<V>() {
                    private Iterator<Entry<K,V>> i = entrySet().iterator();

                    public boolean hasNext() {
                        return i.hasNext();
                    }

                    public V next() {
                        return i.next().getValue();
                    }

                    public void remove() {
                        i.remove();
                    }
                };
            }

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

            public boolean isEmpty() {
                return AbstractMap.this.isEmpty();
            }

            public void clear() {
                AbstractMap.this.clear();
            }

            public boolean contains(Object v) {
                return AbstractMap.this.containsValue(v);
            }
        };
    }
    return values;
}

操作方法

下面看看 AbstractMap 的具體操作集合的方法。

  • 新增
/**
 * 沒有提供實現,子類必須重寫該方法,否則呼叫put()會丟擲異常。
 */
public V put(K key, V value) {
    throw new UnsupportedOperationException();
}
/**
 * 遍歷一個Map,然後將每一個鍵值對put到該Map中。
 */
public void putAll(Map<? extends K, ? extends V> m) {
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
 }
  • 刪除
/**
 * 遍歷entrySet,先找到對應的key的entry,然後刪除。
 */
public V remove(Object key) {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    Entry<K,V> correctEntry = null;
    //遍歷查詢,當某個 Entry 的 key 和 指定 key 一致時結束
    if (key==null) {
        while (correctEntry==null && i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                correctEntry = e;
        }
    } else {
        while (correctEntry==null && i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                correctEntry = e;
        }
    }

    V oldValue = null;
    if (correctEntry !=null) {
        oldValue = correctEntry.getValue();
        //呼叫迭代器的 remove 方法
        i.remove();
    }
    return oldValue;
}
/**
 * 清空entrySet,等價於清空該Map。
 */
public void clear() {
    entrySet().clear();
}
  • 查詢對應的子元素
//遍歷entrySet(),看看是否包含引數key
public boolean containsKey(Object key) {
    Iterator<Map.Entry<K,V>> i = entrySet().iterator();
    if (key==null) {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                return true;
        }
    } else {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                return true;
        }
    }
    return false;
}

//與containsKey方法同理,只是比較的是value
public boolean containsValue(Object value) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (value==null) {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getValue()==null)
                    return true;
            }
        } else {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (value.equals(e.getValue()))
                    return true;
            }
        }
        return false;
  }
  • 獲取元素
//使用 entrySet 迭代器進行遍歷,根據 key 查詢,返回對應的value
public V get(Object key) {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    if (key==null) {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (e.getKey()==null)
                return e.getValue();
        }
    } else {
        while (i.hasNext()) {
            Entry<K,V> e = i.next();
            if (key.equals(e.getKey()))
                return e.getValue();
        }
    }
    return null;
}

兩個子類

除了上面的方法之外,AbstractMap 類中還提供了兩個子類,分別是 SimpleEntry,SimpleImmutableEntry,兩個子類都實現了Map.Entry 以及 Serializable 介面,這是他們的原始碼

  • SimpleEntry
public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable {
    private static final long serialVersionUID = -8499721149061103585L;
    private final K key;
    private V value;

    public SimpleEntry(K var1, V var2) {
        this.key = var1;
        this.value = var2;
    }

    public SimpleEntry(Entry<? extends K, ? extends V> var1) {
        this.key = var1.getKey();
        this.value = var1.getValue();
    }

    public K getKey() {
        return this.key;
    }

    public V getValue() {
        return this.value;
    }

    public V setValue(V var1) {
        Object var2 = this.value;
        this.value = var1;
        return var2;
    }

    public boolean equals(Object var1) {
        if (!(var1 instanceof Entry)) {
            return false;
        } else {
            Entry var2 = (Entry)var1;
            return AbstractMap.eq(this.key, var2.getKey()) && AbstractMap.eq(this.value, var2.getValue());
        }
    }

    public int hashCode() {
        return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode());
    }

    public String toString() {
        return this.key + "=" + this.value;
    }
}
  • SimpleImmutableEntry
public static class SimpleImmutableEntry<K, V> implements Entry<K, V>, Serializable {
    private static final long serialVersionUID = 7138329143949025153L;
    private final K key;
    private final V value;

    public SimpleImmutableEntry(K var1, V var2) {
        this.key = var1;
        this.value = var2;
    }

    public SimpleImmutableEntry(Entry<? extends K, ? extends V> var1) {
        this.key = var1.getKey();
        this.value = var1.getValue();
    }

    public K getKey() {
        return this.key;
    }

    public V getValue() {
        return this.value;
    }

    public V setValue(V var1) {
        throw new UnsupportedOperationException();
    }

    public boolean equals(Object var1) {
        if (!(var1 instanceof Entry)) {
            return false;
        } else {
            Entry var2 = (Entry)var1;
            return AbstractMap.eq(this.key, var2.getKey()) && AbstractMap.eq(this.value, var2.getValue());
        }
    }

    public int hashCode() {
        return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode());
    }

    public String toString() {
        return this.key + "=" + this.value;
    }
}

兩個實現都非常簡單,具體的方法也是大同小異,唯一有區別的是 setValue 這個方法,SimpleEntry 支援 setValue 的操作實現,而 SimpleImmutableEntry 就沒有實現,說明前者為可變集合,後者為不可變集合。

參考:

http://www.importnew.com/29686.html