Java ArrayList Detailed

So far only records concern. JDK1.8

First, the basic properties

1.1 Internal parameters

    //空存储实例。直接new ArrayList()便是以该空数组作为实例
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //默认容量大小,在由空实例进行首次扩容时,扩到到该长度。
    //实际使用中,并未实际存在Capacity这个参数,需要扩容时直接根据旧数组的length进行扩容
    private static final int DEFAULT_CAPACITY = 10;

    //实际存储数组
    transient Object[] elementData;

    //存储元素个数
    private int size;

Three constructor overloads 1.2

    //构建一个空实例,elementData指向容量为0的空数组
    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);
        }
    }

    //以集合初始化创建列表
    //步骤:1. 调用toArray(),将给定集合转成数组(以ArrayList为例,toArray()返回的是实际存在元素的那部分数组,即[0,size))
    //2. 让size直接等于给定集合的数组长度
    //3. 判断size如果为0则直接创建空存储实例,否则使用Arrays.copyOf将给定集合数组复制一份(浅拷贝),作为存储数组
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    // ArrayList 的 toArray()源码,复制[0,size)部分返回
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

Second, operations and strategy

2.1 Dynamic expansion

Expansion strategy: when an array of all full before expansion, the new length = length + old old length * 2

Dynamic expansion has two entrances: expansion for explicit user call ensureCapacity()and added expansion during the implicit elements ensureCapacityInternal(), but are invoked ensureExplicitCapacity()to determine whether the required capacity value based on the incoming expansion, the final operation in the actual expansion grow()process.

    //显式扩容入口方法
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    //隐式扩容入口方法
    //其中参数 minCapacity 值为 size+1,由add方法调用传入
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    //添加方法
    public boolean add(E e) {
        // 传入最小所需容量为size+1
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }


    //计算所需容量,实则不需要计算
    //只是单纯判断当前是否是空实例,为空就话返回 "默认容量"与minCapacity之间的较大值,不为空直接返回minCapacity
    //参数 minCapacity 只有两种情况:
    // 1. 隐式扩容时,如add()传入,其值为 size+1
    // 2. 显式扩容,用户指定
    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);
    }

    //实际扩容方法
    //可以看到扩容策略为:length+length*2
    //然后调用Arrays.copyOf浅复制
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); //旧长度+旧长度*2
        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);
    }

Guess you like

Origin www.cnblogs.com/simpleito/p/10926385.html