美文网首页码农的世界程序员
ArrayList源码解析 初始化和扩容

ArrayList源码解析 初始化和扩容

作者: Upstreamzy | 来源:发表于2019-03-16 13:05 被阅读6次

ArrayList初始化

首先我们来看一段代码:

public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        list1.add(1);

        System.out.println(list1.size());
        System.out.println(list2.size());
    }

emmmmm,这是ArrayList类的最简单的使用了吧,那我们就随着程序运行先去看看构造方法是怎么实现的:

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

那我们再来看看this.elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA到底是什么鬼:

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] 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 = {};

    /**
     * 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;

emmmm从注释中我们可以看出来elementData是存储ArrayList元素的缓冲区(数组),而DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个static类型的Object空数组,static的性质是每个类仅存在一个这种类型的变量。
那么问题来了为什么构造方法不写成这种形式呢?

public ArrayList() {
        this.elementData = new Object[]{};
}

假如我们多次创建ArrayList对象并且多次调用new ArrayList();的话然后就会创建很多个空的Object空数组,而使用jdk所实现的代码不管怎样在程序运行时间内只创建了一个Object空数组,看来写这段代码的作者就是防止创建大量的Object数组导致资源浪费。
好吧我们继续执行执行到了:

list1.add(1);

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;
    }

先忽略掉ensureCapacityInternal(size + 1),那就很简单了就是把新添加进来的元素直接丢进elementData数组的最后面。
那我们来看看ensureCapacityInternal()方法

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

我们还需要看看ensureExplicitCapacity()方法和calculateCapacity()方法。

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

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

还有grow()方法:

/**
     * 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);
    }

emmmm,总算是到头了,通过注释我们了解到grow()方法的作用就是为ArrayList的elemData数组扩展容量的,注意一下这条语句:

int newCapacity = oldCapacity + (oldCapacity >> 1);

话说>>这个符号我都快忘了,第一学期的时候学c语言老师提了一嘴但是没仔细讲,然后我是在那次寒假从图书馆借了一本2004《深入理解计算机系统》然后它的第一章就是讲计算机里面的数据(准确来说是内存)然后我也看不懂于是我就只是做做习题,然后习题里面都是这个玩意(位运算)。

>>是有符号右移,这个数在内存中占到的比特位最高位不变其它向右移,那么>>1就是向右移一位咯,那就是这个数除以2咯。然后你预计要的容量newCapacity就是原来容量oldCapacity的1.5倍了。

但是如果预计的容量newCapacity还是比参数最小容量minCapacity,那就只能用minCapacity作为最小容量了,然后就是把原来的数组元素复制到新的扩大的数组里面。
这我们就看完了我们就该看calculateCapacity()方法了:

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

很显然这个方法就是计算ArrayList的内部最小容量的。
到此我们就可以明确ArrayList的add()方法的作用就是把元素添加到ArrayList里面的,并且要做扩容之类的事情。

相关文章

网友评论

    本文标题:ArrayList源码解析 初始化和扩容

    本文链接:https://www.haomeiwen.com/subject/wfdppqtx.html