Read Code——ArrayList

Posted 小可爱的大笨蛋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Read Code——ArrayList相关的知识,希望对你有一定的参考价值。

成长总是痛苦的,但你不得不去成长。

在日常的开发过程中,我们经常会用到一个类 List ,可以说这个类是必不可少的,完美的代替了数组,使得数组操作更加的方便,更加的友好。在其下,我们进场使用两个类对其进行实例化:ArrayList和LinkedList,其实说实话,LinkedList用到的也不是很多。

1.关于List

List本身是一个接口,继承了Collection,Collection是Java提醒中集合操作的两大阵营的其中之一(另一个是Map)。List定义了一系列的方法,像常用的add,remove,get,set。

2.关于ArrayList


从上图种不难看出,ArrayList实现了List接口,但同时继承了AbstractList,但是AbstractList又实现了List接口,值得一提的是,作者这里使用了模板设计模式,使得整个List的子类实现的过程更加的规范化。

2.1 ArrayList的初始化

当直接new一个ArrayList对象的时候,可以发现,他会之间对一个属性进行赋值。

public ArrayList() 
   	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

elementData 这个属性其实就是一个没有初始化的数组。

/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

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.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;

2.2 ArrayList的添加

add方法可以说是抛开初始化之外用的最多的一个方法了

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by @link Collection#add)
 */
public boolean add(E e) 
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;

总共只有三步:

  • 第一步:确保整个容器的大小;
  • 第二步:将数据存入(从这里可以看出,ArrayList不是线程安全的);
  • 第三步:返回数据。
    接下来,我们进入到 ensureCapacityInternal去看看:
private void ensureCapacityInternal(int minCapacity) 
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

计算一个容量:

private static int calculateCapacity(Object[] elementData, int minCapacity) 
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) 
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    
    return minCapacity;

返回最大的那个容量。
之后需要做一个容器大小的增长:

private void ensureExplicitCapacity(int minCapacity) 
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);

先将容器的大小自增,之后比较现在的大小和实际的大小是否存在误差,防止其溢出,即完成自动扩容。

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 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
     */
    private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    

从上述代码中可以发现,每次扩容的大小是原来的一半。即新的大小应该是:
new = old + old / 2 或 new = old。

以上是关于Read Code——ArrayList的主要内容,如果未能解决你的问题,请参考以下文章