内部有两个共享的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
EMPTY_ELEMENTDATA
是在list为空的时候共享的,这里的为空是确确实实的为空,比如删除干净了;DEFAULTCAPACITY_EMPTY_ELEMENTDATA
是用无参构造器构造一个ArrayList对象的时候默认的数据指向,即new一个新对象的时候其实内部数据并未初始化,在添加元素的时候内部数据数组才会初始化,而也可以根据数据是否指DEFAULTCAPACITY_EMPTY_ELEMENTDATA
来判断内部数据是否已经初始化过
扩容机制
- 数组最大容量:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
- 50%扩容
- 如果
elementData
尚未初始化,则扩容的容量为Math.max(newSize,DEFAULT_CAPACITY)
- 如果最终确定的
newSize>MAX_ARRAY_SIZE
,最终newSize会被确定为Integer.MAX_VALUE
,显然几乎没有机会开到这么大的数组 - 如果传入的
newSize<0
,则表示溢出了,会抛出OutOfMemoryError
remove方法要针对null单独处理
ArrayList
是可以存放null的- 对于
非null
元素判断相等是用的是equals
方法 - 对于
nulll
,判断相等时用的是==
重载方法的调用顺序
如下两个方法重载
public static void test(Object o) {
System.out.println("object:" + o);
}
public static void test(int n) {
System.out.println("int:" + n);
}
在调用的时候,会首先匹配基本类型
的那个,估计是按照类的级别从下往上匹配
迭代器
cursor
指向的是下一个要访问的元素,所以初始化的时候是0
,而判断hasNext()
的时候也就是返回cursor==size
lastRet
指向的是当前元素,所以初始化的时候是-1
,而调用Iterator的remove()
时,逻辑就是删除lastRet
处的元素,然后cursor
后退一位,仍然满足指向下一个元素- 快速失败机制
fail-fast
:modCount - 调用迭代器的方法时为什么不会触发失败机制?因为其内部重新同步了modCount
foreach VS for
- foreach用的是迭代器,在循环是删除元素是会报
ConcurrentModificationException
- for循环可以删除元素,但是要警惕
在for循环删除元素的过程中,lsit的size也会随之改变