zoukankan      html  css  js  c++  java
  • Guava源码学习(三)ImmutableCollection

    基于版本:Guava 22.0

    Wiki:Immutable collections

    0. ImmutableCollection简介

    类似于JDK的Collections.unmodifiableXXX,可以创建不可变集合,是一种防御式编程的体现。

    1. 类图

    这张类图也不完全,ImmutableCollection实际上有十几个子类

    2. 设计思路

    ImmutableCollection是继承于Collection的抽象类,将所有涉及到修改的方法全部设置为final(禁止子类重写),方法体是直接抛出UnsupportedOperationException。

    这样就实现了禁止修改的语义。

    随意举两个例子如下:

      /**
       * Guaranteed to throw an exception and leave the collection unmodified.
       *
       * @throws UnsupportedOperationException always
       * @deprecated Unsupported operation.
       */
      @CanIgnoreReturnValue
      @Deprecated
      @Override
      public final boolean add(E e) {
        throw new UnsupportedOperationException();
      }
    
      /**
       * Guaranteed to throw an exception and leave the collection unmodified.
       *
       * @throws UnsupportedOperationException always
       * @deprecated Unsupported operation.
       */
      @CanIgnoreReturnValue
      @Deprecated
      @Override
      public final boolean remove(Object object) {
        throw new UnsupportedOperationException();
      }

    但是如何初始化ImmutableCollection呢?

    a. ImmutableCollection的子类都实现了of与copyOf方法,通过这两个方法可以直接获取ImmutableCollection的实例。

    b. ImmutableCollection.Builder提供了更加方便的构造器,ImmutableCollection的子类通过实现ImmutableCollection.Builder的关键方法,可以创建ImmutableCollection的实例。

    3. ImmutableList

    简单分析一下ImmutableList的实现

      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()) : list;
        }
        return construct(elements.toArray());
      }

    这个copyOf方法是很有意思的:

    如果发现传入的集合是ImmutableCollection,并且不是完全的集合(由subList这种方法创建的集合),则创建一个拷贝(不再保留对原集合的引用,如果原集合很大,可以减少内存泄漏的可能),如果是完全的集合,则直接返回它的引用。

      /**
       * Returns an immutable list of the elements between the specified {@code
       * fromIndex}, inclusive, and {@code toIndex}, exclusive. (If {@code
       * fromIndex} and {@code toIndex} are equal, the empty immutable list is
       * returned.)
       */
      @Override
      public ImmutableList<E> subList(int fromIndex, int toIndex) {
        checkPositionIndexes(fromIndex, toIndex, size());
        int length = toIndex - fromIndex;
        if (length == size()) {//直接返回整个引用
          return this;
        } else if (length == 0) {
          return of();//返回EMPTY
        } else {
          return subListUnchecked(fromIndex, toIndex);//创建subList
        }
      }
    
      /**
       * Called by the default implementation of {@link #subList} when {@code
       * toIndex - fromIndex > 1}, after index validation has already been
       * performed.
       */
      ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
        return new SubList(fromIndex, toIndex - fromIndex);//限定subList的范围
      }
    
      class SubList extends ImmutableList<E> {
        final transient int offset;
        final transient int length;
    
        SubList(int offset, int length) {
          this.offset = offset;
          this.length = length;
        }
    
        @Override
        public int size() {
          return length;
        }
    
        @Override
        public E get(int index) {//转换下标,从原list的对应位置取值
          checkElementIndex(index, length);
          return ImmutableList.this.get(index + offset);
        }
    
        @Override
        public ImmutableList<E> subList(int fromIndex, int toIndex) {
          checkPositionIndexes(fromIndex, toIndex, length);
          return ImmutableList.this.subList(fromIndex + offset, toIndex + offset);
        }
    
        @Override
        boolean isPartialView() {//标注这是一个不完整的集合
          return true;
        }
      }

    ImmutableList.subList方法的实现,没有创建ImmutableList的副本,而是直接访问原ImmutableList中的元素,当然中间会进行下标的转换。

    由于ImmutableList是不可变的,所以这样做是非常安全的,而且节省了开销。

    4. 与Collections.unmodifiableXXX的区别

    • unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies
    • unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection
    • inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.

    直接引用并发编程网的翻译如下

    • 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;
    • 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;
    • 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。
  • 相关阅读:
    angularJS中的MVC思想?
    angularJs初体验,实现双向数据绑定!使用体会:比较爽
    原生JS去解析地址栏的链接?超好用的解决办法
    HDCMS多图字段的使用?
    sublime添加到鼠标右键打开文件的方法?
    Ajax做列表无限加载和Ajax做二级下拉选项
    Atitit.获取某个服务 网络邻居列表 解决方案
    Atitit. 注册表操作查询 修改 api与工具总结 java c# php js python 病毒木马的原理
    Atitit. 注册表操作查询 修改 api与工具总结 java c# php js python 病毒木马的原理
    Atitit.prototype-base class-based  基于“类” vs 基于“原型”
  • 原文地址:https://www.cnblogs.com/stevenczp/p/7274240.html
Copyright © 2011-2022 走看看