天天看點

[Guava源碼日報](8)ImmutableCollection

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/SunnyYoona/article/details/71080164

不可變集合,顧名思義就是說集合是不可被修改的。集合的資料項是在建立的時候提供,并且在整個生命周期中都不可改變。

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#1-unmodifiablexxx 1. UnmodifiableXXX

JDK提供了UnmodifiableXXX(Collections.unmodifiable)用于生成不可變容器。不可變容器無法修改傳回容器的内容。但是這裡值的是無法通過set或add方法修改容器内的reference的指向,而不是禁止reference指向内容的修改。

public static void test1(){
        List<User> list = Lists.newArrayList(new User());
        list.get(0).setName("yoona");
        list.get(0).setCompany("quanr");
        List<User> unmodifiableList = Collections.unmodifiableList(list);
        System.out.println(unmodifiableList.get(0).getName()); //yoona
        unmodifiableList.get(0).setName("sjf");
        //unmodifiableList.add(new User());
        //unmodifiableList.remove(0);
        System.out.println(unmodifiableList.get(0).getName()); //sjf
}           

Collections.unmodifiableXXX傳回的是原容器的視圖。雖然無法對傳回容器進行修改,但是對原容器的修改,會影響傳回容器的内容。

容器内容的變更也會通過視圖展現出來:

public static void test2(){
        User user = new User();
        user.setName("yoona");
        user.setCompany("quanr");
        List<User> list = Lists.newArrayList(user);
        List<User> unmodifiableList = Collections.unmodifiableList(list);
        // 對原容器的修改
        User user2 = new User();
        user2.setName("sjf");
        list.add(user2);
        // 影響傳回容器
        System.out.println(unmodifiableList.get(1).getName()); //sjf
    }           

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#2-immutablexxx 2. ImmutableXXX

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#21-%E8%AF%B4%E6%98%8E 2.1 說明

(1)提供了不可修改容器的功能,保證傳回的容器不能被調用者修改,并且原容器的修改也不會影響ImmutableXXX。這一點與UnmodifiableXXX不同。

(2)對不可靠的客戶代碼來說,它使用安全,可以在未受信任的類庫中安全的使用這些對象。

(3)線程安全的,Immutable對象在多線程下安全,沒有竟态條件。

(4)不需要支援可變性,可以盡量節省空間和時間的開銷。所有的不可變集合實作都比可變集合更加有效的利用記憶體。

(5)可以被使用為一個常量,并且期望在未來也是保持不變的。

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#22-%E5%8E%9F%E7%90%86 2.2 原理

傳回的對象不是原容器的視圖,而是原容器的一份拷貝。

public static final void test1(){
        User user = new User();
        user.setName("Yoona");
        List<User> list = Lists.newArrayList(user);
        ImmutableList<User> immutableList = ImmutableList.copyOf(list);
        User user2 = new User();
        user2.setName("sjf");
        list.add(user2);
        System.out.println(immutableList.size()); // 1
    }           

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#3%E6%BA%90%E7%A0%81 3.源碼

https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#31-builder 3.1 Builder
public abstract static class Builder<E> {
        static final int DEFAULT_INITIAL_CAPACITY = 4;
        /**
         * 擴容
         * @param oldCapacity
         * @param minCapacity
         * @return
         */
        static int expandedCapacity(int oldCapacity, int minCapacity) {
            if (minCapacity < 0) {
                throw new AssertionError("cannot store more than MAX_VALUE elements");
            }
            // careful of overflow!
            int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
            if (newCapacity < minCapacity) {
                newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
            }
            if (newCapacity < 0) {
                newCapacity = Integer.MAX_VALUE;
            }
            return newCapacity;
        }
        Builder() {
        }
        /**
         * 這是一個抽象方法,添加元素到集合中,具體怎麼添加取決于是什麼樣的集合。具體的實作由ImmutableCollection子類實作
         * @param element 待添加的元素
         * @throws  element為null 抛出空指針異常
         */
        public abstract Builder<E> add(E element);
        /**
         * 使用了可變長參數,添加多個element元素到集合中。
         * 每個生成器類重寫此方法,以傳回其自己的類型。
         * @param elements
         * @throws 如果elements為null,或者包含一個元素為null都會抛出空指針異常
         */
        public Builder<E> add(E... elements) {
            for (E element : elements) {
                add(element);
            }
            return this;
        }
        /**
         * 使用了疊代器Iterable,添加Iterable中的element元素到集合中。
         * 每個生成器類重寫此方法,以傳回其自己的類型。
         * @param elements
         * @throws 如果elements為null,或者包含一個元素為null都會抛出空指針異常
         */
        public Builder<E> addAll(Iterable<? extends E> elements) {
            for (E element : elements) {
                add(element);
            }
            return this;
        }
        /**
         * 使用了疊代器Iterator,添加Iterator中的element元素到集合中。
         * 每個生成器類重寫此方法,以傳回其自己的類型。
         * @param elements
         * @throws 如果elements為null,或者包含一個元素為null都會抛出空指針異常
         */
        public Builder<E> addAll(Iterator<? extends E> elements) {
            while (elements.hasNext()) {
                add(elements.next());
            }
            return this;
        }
        /**
         * 抽象方法,由具體實作類傳回相應類型的ImmutableCollection
         * @return
         */
        public abstract ImmutableCollection<E> build();
    }           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#32-copyintoarrayobject-dstint-offset 3.2 copyIntoArray(Object[] dst,int offset)

複制不可變集合中内容到指定數組dst的指定位置offset。傳回最新的偏移量。

int copyIntoArray(Object[] dst, int offset) {
    for (E e : this) {
      dst[offset++] = e;
    }
    return offset;
  }           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#33-object-toarray 3.3 Object[] toArray()

不可變集合轉變為Object數組。如果不可變集合的長度為0,傳回一個空的Object數組。

Object[] EMPTY_ARRAY = new Object[0];           

如果不可變集合的長度不為0,使用上面提到的copyIntoArray()函數拷貝到一個新的Object數組。

public final Object[] toArray() {
    int size = size();
    if (size == 0) {
      return ObjectArrays.EMPTY_ARRAY;
    }
    Object[] result = new Object[size];
    copyIntoArray(result, 0);
    return result;
  }           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#34-boolean-adde-e 3.4 boolean add(E e)

當試圖為一個不可變集合添加元素時,抛出UnsupportedOperationException異常,表示不可變集合不支援添加元素操作,進而保證集合的不可修改性。

public final boolean add(E e) {
    throw new UnsupportedOperationException();
  }           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#35-boolean-removeobject-object 3.5 boolean remove(Object object)

當試圖從一個不可變集合删除元素時,抛出UnsupportedOperationException異常,表示不可變集合不支援删除元素操作,進而保證集合的不可修改性。

@Deprecated
  @Override
  public final boolean remove(Object object) {
    throw new UnsupportedOperationException();
  }           

同理,也不支援多個元素的添加與删除操作,都會抛出UnsupportedOperationException異常。

@Deprecated
  @Override
  public final boolean addAll(Collection<? extends E> newElements) {
    throw new UnsupportedOperationException();
  }
 @Deprecated
  @Override
  public final boolean removeAll(Collection<?> oldElements) {
    throw new UnsupportedOperationException();
  }           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#36-unmodifiableiteratore-iterator 3.6 UnmodifiableIterator<E> iterator()

通過集合擷取不可變性疊代器UnmodifiableIterator。這是一個抽象方法,具體實作看具體的繼承類。

@Override
  public abstract UnmodifiableIterator<E> iterator();           
https://note.youdao.com/md/preview/preview.html?file=%2Fyws%2Fapi%2Fpersonal%2Ffile%2FWEB878ca0e5a4ec66c331437fc26141ebf2%3Fmethod%3Ddownload%26read%3Dtrue#37-immutableliste-aslist-%E4%B8%8E-createaslist 3.7 ImmutableList<E> asList() 與 createAsList()

從集合得到不可變性連結清單ImmutableList,具體為啥在ImmutableCollection中寫此方法還沒明白。

public ImmutableList<E> asList() {
    ImmutableList<E> list = asList;
    return (list == null) ? (asList = createAsList()) : list;
  }
  ImmutableList<E> createAsList() {
    switch (size()) {
      case 0:
        return ImmutableList.of();
      case 1:
        return ImmutableList.of(iterator().next());
      default:
        return new RegularImmutableAsList<E>(this, toArray());
    }
  }