Guava源碼分析——Immutable Collections(2)

分析過Immutable Collections後,進入具體的數據結構來分析,這一次咱們來看看ImmutableList。做爲線性可重複集合,ImmutableList的底層實現採用了數組,由於不可變集合,就不存插入刪除的操做。數組的下標使得根據index的read的操做,時間複雜度變爲了O(1)。對於ImmutableList的兩種實現,咱們先來看下UML圖。數組

首先,咱們看下構造一個ImmutableList的方法數據結構

@Test
public void constructImmutableList() {
    ImmutableList<Integer> list1 = ImmutableList.of(1, 2, 3, 4);
     ImmutableList<Integer> list2 = ImmutableList.copyOf(Lists.newArrayList(1, 2, 3, 4));
}

首先of()方法被重載了12次(後文會詳細介紹緣由),of()方法的實現,根據參數個數的不一樣,採用了不一樣的實現,1個參數爲ide

 public static <E> ImmutableList<E> of(E element) {
    return new SingletonImmutableList<E>(element);
 }

根據SingletonImmutableList的內部實現能夠看出,對於一個元素的ImmutableList,Guava並無在內部維護一個數組,而是維護了一個元素,而其餘的操做都會針對,單個元素進行了優化,例如contains()方法的實現變爲了equals的比較。具體代碼以下:優化

final class SingletonImmutableList<E> extends ImmutableList<E> {

     final transient E element;

     @Override public boolean contains(@Nullable Object object) {
         return element.equals(object);
     }
}

多個參數的of()方法實現,都會依賴於construct()方法this

 private static <E> ImmutableList<E> construct(Object... elements) {
    return asImmutableList(checkElementsNotNull(elements));
 }

而construct()方法最終依賴於asImmutableList()方法實現,代碼以下:spa

static <E> ImmutableList<E> asImmutableList(Object[] elements, int length) {
    switch (length) {
      case 0:
        return of();//直接返回空數組
      case 1:
        @SuppressWarnings("unchecked") // collection had only Es in it
        ImmutableList<E> list = new SingletonImmutableList<E>((E) elements[0]);//返回SingletonImmutableList,上面分析過
        return list;
      default:
        if (length < elements.length) {//of方法的length和elements.length都是相等的
          elements = arraysCopyOf(elements, length);
        }
        return new RegularImmutableList<E>(elements);
    }
}

RegularImmutableList內部維護Object數組,對於集合接口的實現,所有依賴於對數組下標和偏移量的實現設計

class RegularImmutableList<E> extends ImmutableList<E> {
  private final transient int offset;
  private final transient int size;
  private final transient Object[] array;

  RegularImmutableList(Object[] array, int offset, int size) {
    this.offset = offset;
    this.size = size;
    this.array = array;
  }

  RegularImmutableList(Object[] array) {
    this(array, 0, array.length);
  }

  @Override
  @SuppressWarnings("unchecked")
  public E get(int index) {
    Preconditions.checkElementIndex(index, size);
    return (E) array[index + offset];//對於集合的操做,所有轉換爲對數據的index和offset的操做,時間複雜度變爲O(1)
  }

}

其中有一個方法實現的很是巧妙,subListUnchecked()方法,實現並無構造新的Object[]數組,而是在利用原有的數組,但偏移量有所改變。全部的寫操做都已經被屏蔽,因此Object[]數組成爲了避免可變,截取操做只是變成了對原有Object[]上下界的操做。節省了不少空間code

 ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
    return new RegularImmutableList<E>(
        array, offset + fromIndex, toIndex - fromIndex);
 }

仔細的童鞋能夠發現,ImmutableList的of()方法,被重載了12次,爲何Guava的設計者不適用可變參數列表呢?緣由在於,改進使用帶泛型可變參數的方法時的編譯器警告和錯誤提示,若是在泛型與可變參數列表同時適用會產生編譯警告和堆污染,Guava本身重載了11次of方法,根據不一樣的參數個數,並且建議你of方法一次性傳11個參數就能夠了(良好的代碼書寫,告訴咱們不要這樣作)。htm

另外一個須要分析的就是ImmutableList的copyOf方法,若是copyOf的傳參是一個ImmutableCollection(非部分視圖),其實並無真正的進行了copy操做,若是是非ImmutableCollection,那麼,就會進行真正的copy。blog

public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
    if (elements instanceof ImmutableCollection) {
      @SuppressWarnings("unchecked") // all supported methods are covariant
      ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
      return list.isPartialView()
          ? ImmutableList.<E>asImmutableList(list.toArray())//isPartialView==true,進行copy
          : list;//直接返回,由於不可變
    }
    return construct(elements.toArray());//進行copy
  }
相關文章
相關標籤/搜索