Immutable的集合體系,還有中很重要的集合沒有介紹,就是ImmutableMap,經過UML圖,能夠看出ImmutableMap的結構體系。數組
首先來看一下ImmutableBiMap,由於普通ImmutableMap的實現依賴於它。ImmutableBiMap在ImmutableMap的基礎上,加入inverse()等方法,可使鍵值反轉。ImmutableBiMap的構造,也是根據元素個數的不一樣,使用不一樣的實現(0-->EmptyImmutablBiMap,1-->SingletonImmutablBiMap,n(n>=2)-->RegularImmubtalMap),代碼以下所示:數據結構
public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V> implements BiMap<K, V> { public static <K, V> ImmutableBiMap<K, V> of() { //Empty元素內部,不維護存儲結構,inverse()方法直接返回this return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE; } public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) { //單個元素構造時,返回此類,內部維護兩個元素K,V,inverse()時,返回V,K的SingletonImmutableBiMap return new SingletonImmutableBiMap<K, V>(k1, v1); } public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) { //多個元素構造是,返回此類,內部維護兩個Entry[]集合,一個以key做爲hashbucket的位置,
//另外一個以value做爲hashbucket的位置,用於inverse()的時候,key-value的反轉 return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2)); } }
copyOf()方法,在ImmutableCollections中實現的原則就是,若是copyOf()的仍是一份ImmutableCollections集合,那麼只是進行引用的賦值,由於集合自己不可變。app
看過ImmutableBiMap以後,在回頭看ImmutableMap就簡單了不少,只是在ImmutableBiMap基礎上去除了inverse()方法,並在內部爲戶單一數組(hashbucket)ide
不須要維護反轉的數組。在無元素和單一元素構造的時候,直接調用ImmutableBiMap.of()和ImmutableBiMap.of(K,V)方法,代碼以下所示:ui
public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable { /** * Returns the empty map. This map behaves and performs comparably to * {@link Collections#emptyMap}, and is preferable mainly for consistency * and maintainability of your code. */ public static <K, V> ImmutableMap<K, V> of() { return ImmutableBiMap.of(); } /** * Returns an immutable map containing a single entry. This map behaves and * performs comparably to {@link Collections#singletonMap} but will not accept * a null key or value. It is preferable mainly for consistency and * maintainability of your code. */ public static <K, V> ImmutableMap<K, V> of(K k1, V v1) { return ImmutableBiMap.of(k1, v1); } }
多個元素構造的時候,返回RegularImmubtalMap,與RegularImmutableBiMap內部實現大同小異,去除對反轉(值-鍵)的數組維護,去除inverse()等方法。this
最後簡單的闡述一下ImmutableSortedMap的實現,ImmutableMap單一元素和空元素的實現,就不詳細說了,有興趣的讀者能夠本身看看。多元素實現的時候,spa
ImmutableSortedMap的具體實現類是RegularImmutableSortedMap,有意思的是,它的內部維護key和value的數據結構是兩個List,那麼可想而知,排序早在構造的時候就已經完成了,而事實確實是這樣,具體代碼以下所示:code
@SuppressWarnings("unchecked") public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { //將排序器和entires傳入fromEntries方法 return fromEntries(Ordering.natural(), false, 4, entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4)); }
static <K, V> ImmutableSortedMap<K, V> fromEntries( Comparator<? super K> comparator, boolean sameComparator, int size, Entry<K, V>... entries) { for (int i = 0; i < size; i++) { Entry<K, V> entry = entries[i]; entries[i] = entryOf(entry.getKey(), entry.getValue()); } if (!sameComparator) { sortEntries(comparator, size, entries);//遍歷entries排序 validateEntries(size, entries, comparator); } return fromSortedEntries(comparator, size, entries); }
static <K, V> ImmutableSortedMap<K, V> fromSortedEntries( Comparator<? super K> comparator,int size,Entry<K, V>[] entries) { if (size == 0) { return emptyMap(comparator); } //遍歷排序以後的entries,分開key和value,分別組成各自的List ImmutableList.Builder<K> keyBuilder = ImmutableList.builder(); ImmutableList.Builder<V> valueBuilder = ImmutableList.builder(); for (int i = 0; i < size; i++) { Entry<K, V> entry = entries[i]; keyBuilder.add(entry.getKey()); valueBuilder.add(entry.getValue()); } return new RegularImmutableSortedMap<K, V>( new RegularImmutableSortedSet<K>(keyBuilder.build(), comparator), valueBuilder.build()); }
ImmutableMap中的Entry,也是被Guava從新實現,增長了bucket的計算邏輯,以下圖UML:orm
AbstractMapEntry在原有Map.entry基礎上,將寫操做,置爲直接拋異常,ImmutableEntry實現getKey()和getValue(),ImmutableMapEntry再加入bucket的計算和維護方法(鏈表),最終反映到NonTerminalMapEntry和TerminalEntry,對於這兩個類,TerminalEntry爲bucket鏈表的尾結點,因此實現以下:blog
static final class TerminalEntry<K, V> extends ImmutableMapEntry<K, V> { TerminalEntry(ImmutableMapEntry<K, V> contents) { super(contents); } TerminalEntry(K key, V value) { super(key, value); } @Override @Nullable ImmutableMapEntry<K, V> getNextInKeyBucket() { //尾節點,因此沒有nuext return null; } @Override @Nullable ImmutableMapEntry<K, V> getNextInValueBucket() { //尾節點,因此沒有nuext return null; } }
而NonTerminalMapEntry的構造則須要傳入下一個Entry
private static final class NonTerminalMapEntry<K, V> extends ImmutableMapEntry<K, V> { private final ImmutableMapEntry<K, V> nextInKeyBucket; NonTerminalMapEntry(K key, V value, ImmutableMapEntry<K, V> nextInKeyBucket) { super(key, value); this.nextInKeyBucket = nextInKeyBucket; } NonTerminalMapEntry(ImmutableMapEntry<K, V> contents, ImmutableMapEntry<K, V> nextInKeyBucket) { super(contents); this.nextInKeyBucket = nextInKeyBucket; } @Override ImmutableMapEntry<K, V> getNextInKeyBucket() { //同一個bucket中的下一個Entry return nextInKeyBucket; } @Override @Nullable ImmutableMapEntry<K, V> getNextInValueBucket() { //BiMap纔會維護Value的Bucket return null; } }
那麼在構造的時候,若是產生hash衝突,就是用nonTerminalMapEntry,代碼以下所示:
RegularImmutableMap(Entry<?, ?>[] theEntries) { int size = theEntries.length; entries = createEntryArray(size); int tableSize = Hashing.closedTableSize(size, MAX_LOAD_FACTOR); table = createEntryArray(tableSize); mask = tableSize - 1; for (int entryIndex = 0; entryIndex < size; entryIndex++) { @SuppressWarnings("unchecked") // all our callers carefully put in only Entry<K, V>s Entry<K, V> entry = (Entry<K, V>) theEntries[entryIndex]; K key = entry.getKey(); V value = entry.getValue(); checkEntryNotNull(key, value); int tableIndex = Hashing.smear(key.hashCode()) & mask; @Nullable ImmutableMapEntry<K, V> existing = table[tableIndex]; // prepend, not append, so the entries can be immutable //在構造是,若是產生hash衝突,那麼直接的append到terminal的前面 ImmutableMapEntry<K, V> newEntry = (existing == null) ? new TerminalEntry<K, V>(key, value) : new NonTerminalMapEntry<K, V>(key, value, existing); table[tableIndex] = newEntry; entries[entryIndex] = newEntry; checkNoConflictInBucket(key, newEntry, existing); } }