引言
今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口的 实现类之一,也是HashMap、TreeMap、ConcurrentHashMap 等的父类,它提供了Map 接口中方法的基本实现(关于Map接口有疑惑的同学可参考 Java集合类根接口:Collection 和 Map)
因为 AbstractMap 类是实现Map接口的抽象类,所以其内部也包含了操作子元素的实体接口 Entry,其源码方法对元素的操作都是基于 Entry 的视图实现的。
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() 返回的集合视图实现的,这是他们的源码:
// 返回一个AbstractSet的实现,包含了所有的key public SetkeySet() { if (keySet == null) { keySet = new AbstractSet() { public Iteratoriterator() { return new Iterator() { private Iterator<Entry> 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; }
// 返回一个AbstractCollection的实现,包含了所有的value public Collectionvalues() { if (values == null) { values = new AbstractCollection() { public Iteratoriterator() { return new Iterator() { private Iterator<Entry> 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 m) { for (Map.Entry e : m.entrySet()) put(e.getKey(), e.getValue()); }
/** * 遍历entrySet,先找到对应的key的entry,然后删除。 */ public V remove(Object key) { Iterator<Entry> i = entrySet().iterator(); EntrycorrectEntry = null; //遍历查找,当某个 Entry 的 key 和 指定 key 一致时结束 if (key==null) { while (correctEntry==null && i.hasNext()) { Entrye = i.next(); if (e.getKey()==null) correctEntry = e; } } else { while (correctEntry==null && i.hasNext()) { Entrye = 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> i = entrySet().iterator(); if (key==null) { while (i.hasNext()) { Entrye = i.next(); if (e.getKey()==null) return true; } } else { while (i.hasNext()) { Entrye = i.next(); if (key.equals(e.getKey())) return true; } } return false; } //与containsKey方法同理,只是比较的是value public boolean containsValue(Object value) { Iterator<Entry> i = entrySet().iterator(); if (value==null) { while (i.hasNext()) { Entrye = i.next(); if (e.getValue()==null) return true; } } else { while (i.hasNext()) { Entrye = i.next(); if (value.equals(e.getValue())) return true; } } return false; }
//使用 entrySet 迭代器进行遍历,根据 key 查找,返回对应的value public V get(Object key) { Iterator<Entry> i = entrySet().iterator(); if (key==null) { while (i.hasNext()) { Entrye = i.next(); if (e.getKey()==null) return e.getValue(); } } else { while (i.hasNext()) { Entrye = i.next(); if (key.equals(e.getKey())) return e.getValue(); } } return null; }
除了上面的方法之外,AbstractMap 类中还提供了两个子类,分别是 SimpleEntry,SimpleImmutableEntry,两个子类都实现了Map.Entry 以及 Serializable 接口,这是他们的源码
public static class SimpleEntryimplements Entry, 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 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; } }
public static class SimpleImmutableEntryimplements Entry, 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 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 就没有实现,说明前者为可变集合,后者为不可变集合。