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()方法直接返回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);
    }
  }
相關文章
相關標籤/搜索