ArrayList动态扩容及其验证(JDK12源码分析)

ArrayList动态扩容(JDK12)

最近有在温习一下java容器,今天就开始读一下ArrayList的动态扩容

ArrayList是什么?

ArrayList叫做动态数组,实现了长度可变的数组, 在内存中分配连续的空间.

优缺点

优点:
遍历元素和随机访问元素的效率较高
缺点:
添加和删除需要大量移动元素,效率低;按照内容查询效率低;


ArrayList是在object包中,继承于Collection与其子类AbstractList的.

所有实现了的接口有:Serializable(序列化), Cloneable(克隆), Iratable(迭代器),Collection(集合), List(列表),RandomAccess(随机存取)
ArrayList继承关系

动态扩容

初始化:

三个初始化方法:

  • 默认构造器
/**
     * Constructs an empty list with an initial capacity of ten.
     * (构造一个初始容量为10的空列表)
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
/**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
	 *(为默认空实例提供的空的数组实例,用来区分EMPTY_ELEMENTDATA,以便了解当添加第一个元素时是如何扩容的)
     */
     //简而言之就是个空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • 用指定的大小来初始化内部的数组
/**
     * Constructs an empty list with the specified initial capacity.
     *(用指定的初始容量构造一个空的列表)
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    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);
        }
    }
  • 用一个ICollection对象来构造,并将该集合的元素添加到ArrayList
/**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     * (构造一个包含了该集合的列表,并按照集合的迭代器依次返回)
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
    	//将集合C中的内容转化为数组形式存放
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

这里这一段可能不易理解

            // defend against c.toArray (incorrectly) not returning Object[]
            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
            //elementData的对象不等于toArray()方法的运行时对象,保证了这个,再进行拷贝
            //否则数组有可能发生错乱
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
-----------------------------------------------------------------------------------------------------------------------------------
		/** 	 toArray()方法
		//简而言之意思就是:返回一个数组,这个数组是按照之前的顺序返回得到的
     * Returns an array containing all of the elements in this collection.
     * If this collection makes any guarantees as to what order its elements
     * are returned by its iterator, this method must return the elements in
     * the same order. The returned array's {@linkplain Class#getComponentType
     * runtime component type} is {@code Object}.
     *
     
     //返回一个运行时组件类型为对象的数组,包含所有该集合中的元素
     * @return an array, whose {@linkplain Class#getComponentType runtime component
     * type} is {@code Object}, containing all of the elements in this collection
     */
    Object[] toArray();

容量的变化

容量的变化是先从创建开始的,然后添加元素,伴随着容量的变化;

元素的添加

 /**
     * This helper method split out from add(E) to keep method
     * bytecode size under 35 (the -XX:MaxInlineSize default value),
     * which helps when add(E) is called in a C1-compiled loop.
     *(这个辅助方法是从add(E)方法分离而来的,为了保持方法字节码低于35,这将有助于add(E)方法调用C1编译循环)(至于咋优化的咱也不想知道)
     */
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

    /**
     * Appends the specified element to the end of this list.
     *(追加指定的元素到列表的末端)
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        modCount++;
        //此处调用上面的那个方法
        add(e, elementData, size);
        return true;
    }

元素的扩容

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *(增加容量来保证至少能够容纳这些元素)
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    private Object[] grow() {
        return grow(size + 1);
    }

    /**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by 50% if that suffices.
     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
     *(返回一个至少与给定的最小容量一样大的容量)
     *(如果足够的话,返回增加当前容量增加50%的容量)
     *(除非给定的(传参传进来的)最小容量比MAX_ARRAY_SIZE的值要大,不然不会返回一个比MAX_ARRAY_SIZE还大的值)
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        //(oldCapacity >> 1)右移操作,右移一位,二进制数右移一位,左边补0;相当于除以二;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        //三元运算符,(判断表达式)? A : B;加入判断表达式得出为true,则返回A,否则返回B
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

再贴出hugeCapacity()方法

//无需多言,相信大家都看的懂
 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }

调试并总结

调试代码

仍然贴代码

public class test {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        System.out.println(getArrayListCapacity(arrayList));
        for (int i = 0; i < 5; i++) {
            arrayList.add(i);
            for (int j = 0; j < 5; j++) {
                arrayList.add(j);
                //想看到更多的容量值变换,可以将i,j的值变大,并在循环体打印
                // System.out.println(getArrayListCapacity(arrayList));
            }
            System.out.println(getArrayListCapacity(arrayList));
        }

    }

    //利用反射机制获取当前ArrayList对象的容量
    public static int getArrayListCapacity(ArrayList arrayList) {
        Class<ArrayList> arrayListClass = ArrayList.class;
        try {
            Field field = arrayListClass.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] objects = (Object[])field.get(arrayList);
            return objects.length;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            return -1;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            return -1;
        }
    }
}

输出内容

在这里插入图片描述

总结

结果也是十分清晰:
创建时为0,然后马上给了10的容量值,当容量到达了10后,再次添加到10的1.5倍,一直如此,这就是ArrayList的动态扩容了.

发布了25 篇原创文章 · 获赞 8 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/FungLi_notLove/article/details/103773021