Guava源码分析——Immutable Collections(4)
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()方法直接返回thisreturn (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;}public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {//單個元素構造時,返回此類,內部維護兩個元素K,V,inverse()時,返回V,K的SingletonImmutableBiMapreturn 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集合,那么只是進行引用的賦值,因為集合本身不可變。
看過ImmutableBiMap之后,在回頭看ImmutableMap就簡單了很多,只是在ImmutableBiMap基礎上去除了inverse()方法,并在內部為戶單一數組(hashbucket)
不需要維護反轉的數組。在無元素和單一元素構造的時候,直接調用ImmutableBiMap.of()和ImmutableBiMap.of(K,V)方法,代碼如下所示:
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()等方法。
最后簡單的闡述一下ImmutableSortedMap的實現,ImmutableMap單一元素和空元素的實現,就不詳細說了,有興趣的讀者可以自己看看。多元素實現的時候,
ImmutableSortedMap的具體實現類是RegularImmutableSortedMap,有意思的是,它的內部維護key和value的數據結構是兩個List,那么可想而知,排序早在構造的時候就已經完成了,而事實確實是這樣,具體代碼如下所示:
@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,分別組成各自的ListImmutableList.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:
AbstractMapEntry在原有Map.entry基礎上,將寫操作,置為直接拋異常,ImmutableEntry實現getKey()和getValue(),ImmutableMapEntry再加入bucket的計算和維護方法(鏈表),最終反映到NonTerminalMapEntry和TerminalEntry,對于這兩個類,TerminalEntry為bucket鏈表的尾結點,所以實現如下:
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@NullableImmutableMapEntry<K, V> getNextInKeyBucket() {//尾節點,所以沒有nuextreturn null;}@Override@NullableImmutableMapEntry<K, V> getNextInValueBucket() {//尾節點,所以沒有nuextreturn 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;}@OverrideImmutableMapEntry<K, V> getNextInKeyBucket() {//同一個bucket中的下一個Entryreturn nextInKeyBucket;}@Override@NullableImmutableMapEntry<K, V> getNextInValueBucket() {//BiMap才會維護Value的Bucketreturn 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>sEntry<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);}}?
轉載于:https://www.cnblogs.com/pona/p/4564256.html
總結
以上是生活随笔為你收集整理的Guava源码分析——Immutable Collections(4)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 漏洞扫描工具AppScan下载网盘
- 下一篇: 下拉到底部加载更多