尼古丁奥斯托洛夫斯基

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

       最近有被问到ArrayList的扩容问题,决定学习一下ArrayList的源码。之前有在网上看到jdk6的分析好像是说在同构无参构造的时候就进行了初始容量的赋值。我这边只有jdk8,所以下面是一些我对于在jdk8中ArrayList扩容的理解。

  首先点进ArrayList中的构造方法,发现并没有初始容量赋值的操作。

 

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //空数组

    transient Object[] elementData; //空数组

    private static final int DEFAULT_CAPACITY = 10; //默认容量

  在这个两个构造里面并没有看到直接初始容量的操作。

  

  public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

  既然在初始化的时候没有初始容量,然后去add方法里面看看,这里面有个“确保内部容量”的ensureCapacityInternal()方法,点进去继续看

private void ensureCapacityInternal(int minCapacity) {
        //第一次进来条件成立 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //10 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } public static int max(int a, int b) { return (a >= b) ? a : b; }

  可以看出来,在第一次执行这个ensureCapacityInternal()方法时,可以看出来第一次执行的时候初始化数组的默认容量,接着看下面这个“确保明确容量”的ensureExplicitCapacity()方法

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 假设第一次: 10>0 条件成立
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

  接着继续看这个grow()方法

private void grow(int minCapacity) {
        // 假设第一次执行,oldCapacity=0,右移一位加上oldCapacity的newCapacity=0。
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); //右移一位: oldCapacity/2
        if (newCapacity - minCapacity < 0)//此时条件成立,将之前默认的10的容量赋值给这个newCapacity
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0) //这个条件在数据量的很大的时候才能成立
            newCapacity = hugeCapacity(minCapacity); //大数据量的时候会触发这个hugeCapacity()方法
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity); //最后会触发一个copyOf()的方法,
    }

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 

ArrayList内部时数组结构的,数组的容量在初始化的时候就确定了并不能修改,所以这边的扩容,应该会是通过这个copyOf方法进行指定长度数组的赋值来实现ArrayList的动态扩容的。

 

   public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

 

在这个copyOf()方法之后,先是进行一个三元运算符的判断,由于这个newType是ArrayList中的Object数组,所以在这个判断条件的基础上前者成立,即T[] copy = new Object[newLength] . 最后调用System.arraycopy(原来的源数组,起始复制的坐标,复制的目标数组,开始复制的坐标,复制的长度)方法。将新数组复制成功。

以上如有问题,请不吝指正!

 

  

posted on 2018-11-07 14:38  酷酷的COOL  阅读(153)  评论(0)    收藏  举报