zoukankan      html  css  js  c++  java
  • 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个参数为

     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()方法

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

    而construct()方法最终依赖于asImmutableList()方法实现,代码如下:

    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[]上下界的操作。节省了很多空间

     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个参数就可以了(良好的代码书写,告诉我们不要这样做)。

    另一个需要分析的就是ImmutableList的copyOf方法,如果copyOf的传参是一个ImmutableCollection(非部分视图),其实并没有真正的进行了copy操作,如果是非ImmutableCollection,那么,就会进行真正的copy。

    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
      }
  • 相关阅读:
    springboot初始篇(一)
    SpringBoot使用数据库JdbcTemplate(三)
    java实现分页查询
    设计模式之单例模式
    ❤️考研数学公式❤️
    ❤️图的遍历❤️
    图的存储
    图的基本概念
    森林与二叉树的应用
    树相关的代码题
  • 原文地址:https://www.cnblogs.com/pona/p/4545989.html
Copyright © 2011-2022 走看看