Java集合類原始碼解析:AbstractMap
目錄
引言
今天學習一個Java集合的一個抽象類 AbstractMap ,AbstractMap 是Map介面的 實現類之一,也是HashMap、TreeMap、ConcurrentHashMap 等的父類,它提供了Map 介面中方法的基本實現(關於Map介面有疑惑的同學可參考 Java集合類根介面:Collection 和 Map)
原始碼解析
因為 AbstractMap 類是實現Map介面的抽象類,所以其內部也包含了操作子元素的實體介面 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 就沒有實現,說明前者為可變集合,後者為不可變集合。