分析过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 }