一、层级关系
二、初始化方式
(1)Listlist = new ArrayList<>();public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
第一个结论:ArrayList底层是数组
第二个结论:若用无参构造器的方式实例化ArrayList,只是声明了数组,还未分配空间
(2)Listlist = new ArrayList<>(10);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); }}private static final Object[] EMPTY_ELEMENTDATA = {};
补充第二结论:若用有参构造器的方式实例化ArrayList且initialCapacity大于0,则既声明了数组,也分配了空间
三、基本方法的使用
add
- 流程图
- 源码解析
public boolean add(E e) { //校验数组容量,若空间不够则扩容复制生成一个新的数组 ensureCapacityInternal(size + 1); //赋值 elementData[size++] = e; return true;}private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}/** * 若数组是通过无参构造器的方式实例化的话,返回的minCapacity为10,最后会通过grow方法复制生成一个大小为10的数组 * 若数组是通过有参构造器的方式实例化的话,返回的minCapacity为当前要操作的数组下标,不建议声明小于10的数组空间,因为这样前几次add都要去扩容复制生成一个新的数组 */private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);}//扩容大小:原数组大小 + 原数组大小/2private 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);}
-
其它说明
- 初始化ArrayList时,不建议声明小于10的容量,因为这样前几次add都要去扩容复制生成一个新的数组
- Arrays.copyOf(T[] original, int newLength):该方法会创建一个新的数组
remove
- 流程图
- 源码解析
public E remove(int index) { //检查index是否 >= size,若大于则报数组越界异常 rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue;}
-
其它说明
- System.arraycopy - 浅复制
public static void arraycopy( Object src, //源数组 int srcPos, //源数组要复制的起始位置 Object dest, //目标数组 int destPos, //目的数组放置的起始位置 int length //复制长度 )
四、补充
- ArrayList是线程不安全的,表现在多线程下add和remove可能会发生数组越界
- 不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁