List在工作中是很常用的一个集合

它有3个构造方法

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    // 构建一个初始容量是10的ArrayList
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    // 根据给定的初始容量initialCapacity构建一个ArrayList
    // 如果initialCapacity>0则直接直接创建容量为initialCapacity的ArrayList
    // 如果initialCapacity=0则直接使用EMPTY_ELEMENTDATA空集合
    // 如果initialCapacity<0,则出错。
    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);
        }
    }
    // 将给定的集合转换为ArrayList
    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;
        }
    }    
}

平时我们都是这样声明的
List test = new ArrayList()
代表这里的第一种实例化方式,初始容量为10,当ArrayList中的元素超过10个以后,会重新分配内存空间,使数组的大小增长到16。

ps:在JDK1.5之前初始化的时候其实调用了this(10)给了初始大小,但是在JDK1.7之后如果new ArrayList()之后没有add元素进去,其实这个时候是没有进行初始化大小的.

只有在add第一个元素的时候,才会初始化大小为10,可以看到这里的size其实是一个变量,并不是List内的数组的长度,在扩容之后,把新add进去的这个元素放到之前数组长度的下一个index的位置

java list contain方法如何忽略大小写 java设置list大小_数组

这个ensureCapacityInternal方法在后面第二次第三次扩容的时候也会用到,这里会和第一次的数组引用对象指定的地址进行比较,验证是不是第一次进行扩容

java list contain方法如何忽略大小写 java设置list大小_ci_02

modCount代表当前List被调整大小的次数,这里的minCapacity看上图可知还是元素的个数(size) + 1,当元素个数第一次超过10的时候,第一次触发扩容

java list contain方法如何忽略大小写 java设置list大小_数组_03

在扩容的时候,会拿原先的oldCapacity/2 + oldCapacity,这里这个oldCapacity可能为奇数,是偶数的话就是1.5倍了,第一次扩容的时候oldCapacity=10,newCapacity=15,因为数组下标是从0开始的,所以长度也就变成了16.

这里可以看到是用int表示的容量,那么就有可能因为数组太大而溢出,
int的最大值是2^31 - 1因为虽然int是4个字节(byte),1个字节8位(bit),就是32位,但是最高位被拿来当符号位了,正数0,负数1.那么根据二进制的求和公式,四位二进制1111=2 ^ 4 - 1=15,三十一位则为2 ^ 31 -1
3/2X = 2 ^ 31 -1(int的最大值)

当溢出了newCapacity - minCapacity < 0,那么就会取原先的size+1为新的数组长度,只扩容1个长度来存放元素,其实这个临界值可以计算出来,(2 ^ 31 -1)*2/3就是这个临界值
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8据注释说是因为一些虚拟机会放一些头信息在里面

这个newCapacity最后+1+1一直+最后也会加到一个值,这个值肯定不能超过(2 ^ 31 -1)这里设置的是(2 ^ 31 -1)-8

当超过这个值的时候如果size+1已经溢出了这个时候会抛异常,不然就会和(2 ^ 31 -1)-8进行比较,进行三段式判断,可以看到最后的最大大小就是2 ^ 31 -1也就是int的最大值

java list contain方法如何忽略大小写 java设置list大小_ci_04

java list contain方法如何忽略大小写 java设置list大小_ci_05

java list contain方法如何忽略大小写 java设置list大小_List_06

最后就是利用Arrays.copyOf(elementData, newCapacity);把原数组copy到一个扩容之后的新数组里