通过ArrayList存在的位置,我们就可以看出他是实现了List接口,并且同时拥有List和Collection的所有方法。
在ArrayList同样是采用的数组来进行存储的。用来存储的属性是elementData, 记录当前存储有效数据大小的是size。
elementData : 用来存储当前实际的数据(实际就是一个数组)
transient Object[] elementData;
size: 用来存储当前有效数据的长度
private int size;
DEFAULT_CAPACITY:用来存储默认的数组初始容量:
private static final int DEFAULT_CAPACITY = 10;
DEFAULTCAPACITY_EMPTY_ELEMENTDATA: 用来存储默认大小的空实例的共享空数组实例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
利用空参创建的集合,在底层创建的是一个默认长度为0的数组
当添加一地个元素时,底层会创建一个新的长度为10的数组(除了第一个元素其他默认值为空)
当存放数据的数组存满时,会扩容1.5被
如果一次添加多个元素时,1.5倍还放不下时,则新创建数组的长度以实际为准
例如当前数组有10个元素,当下一次在一次性添加50个数据,大于了10的1.5倍,此时数组就会直接扩容到60个长度。
由上可知当前创建的是一个空参的集合,默认的数组长度是为0的,当第一次使用add方法后
首先会调用add(E e) 方法,在这个方法里面首先会调用 ensureCapacityInternal()方法
ensureCapacityInternal是先判断当前的 elementData 是不是为空,由于我们这边是第一次进行添加,所以默认值肯定为空的,所以进入if里面的方法体,计算出当前需要添加的数据有没有超过默认长度10,要是超过了就让当前添加的数据长度作为新的添加元素长度然后调用ensureExplicitCapacity()方法
首先先修改modCount(记录当前数组修改次数属性)加1,然后判断当前传入的长度减去数组的实际长度是否大于0,如果大于0就说明当前数组长度不够,然后就需要调用扩容方法grow()。
在grow方法中,首先会记录原始的数组长度,然后计算出新的数组长度(通过原始数据长度 + 原始数据长度 向右位移一位,相当于就是除以2。例如:原始长度为10,那么计算出的新长度就是10 + 10 / 2 = 15 就相当于扩容了1.5倍)。在下一步就是判断新计算出的数组长度减去我们需要扩容的长度是否大于0(意思就需要判断当前加入的数据如果是20条数据,但是新计算出来的长度为15,所以就不够存放新的数据,然后就需要在次修改新的数组长度,将长度直接改为需要的长度大小)。在然后就需要判断当前数组的大小是否已经超过了当前数组能够存储的数据的最大长度,如果大于了就会调用hugeCapacity().
如果当前的长度小于0就抛出异常,否则就判断当前需要的长度是否大于最大当前集合能够存储的最大数据长度,如果大于就直接赋值为Integer的最大值长度,否则就复制为当前数组最大值。
回到上一步当判断完成后,要是没有异常,就直接执行最后一句 elementData = Arrays.copyOf(elementData, newCapacity);
执行就是将创建一个当前计算出的新数组长度的数组,并且将原始的数据放入到新创建的数组中。
当完成以上步骤后,就可以将当前添加的元素加入到size+1的位置了,并且让size++。这样就完成的数据的新增。
评论
登录后才可以进行评论哦!