ArrayList
List,RandomAccess,Cloneable,Serializable
–>AbstractList–>AbstractCollection
fail-fast的特性,每次扩容后的容量为当前容量+当前容量/2。
静态常量
// 默认初始化大小
private static final int DEFAULT_CAPACITY = 10;
// 默认初始化数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 同样的默认初始化数组,1.8新增
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
成员变量
// 底层数组
transient Object[] elementData; // non-private to simplify nested class access
// 元素数量
private int size;
初始化时可使用带参数的构造函数ArrayList(int initialCapacity)
,此时会构造一个指定大小的底层数组作为ArrayList的实现。若使用默认的无参构造函数,此时仅使用一个空的数组作为ArrayList的实现。
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
ArrayList的无参构造指定一个static final
的空数组作为底层实现,并在第一次对ArrayList进行更改的时候将其容量扩大为DEFAULT_CAPACITY
或更大。注意,若在有参构造函数传入0作为参数,elementData
同样会直接指向一个static final
的空数组。
扩容
// 数组最大长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 每次扩容为原来的1.5倍
private 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);
}
// 若超过最大容量,尝试以Integer.MAX_VALUE开辟空间
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
clone的使用
clone()返回对象的一个浅复制,如果对象是基本类型或其包装类型,则相当于对其进行复制,若是其他对象,则仅复制其引用。
fail-fast
ArrayList不是线程安全的,若使用iterator()得到了迭代器,随后在其他线程进行了增加或删除操作,在当前线程使用迭代器进行next(),previous(),add(),remove()等操作时,均会抛出ConcurrentModificationException(继承至RuntimeException)。
具体实现:
在ArrayList中定义了modCount变量,若在AbstractList(ArrayList)中进行了添加删除操作,则modCount的值均会进行增加。在使用iterator()得到迭代器时,迭代器将复制modCount的值,并在进行next(),previous(),add(),remove()等操作前检验该值是否AbstractList(ArrayList)中的值相同,若不相同,则抛出ConcurrentModificationException异常。并在成功进行添加删除操作后将该值与AbstractList(ArrayList)的值进行同步。
添加删除操作的底层实现
ArrayList在进行add(),remove()等操作时,底层是通过调用
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
方法将需要移动的内存进行前移或后移。同时将不需要的内存置null保证gc的顺利进行。
subList和Iterator的安全性
subList(int fromIndex, int toIndex)方法并没有新建一个ArrayList对象,而是通过一个内部类SubList(extends AbstractList)(里面包含子表相对于原表的偏移量,通过直接调用ArrayList的方法进行操作)。在创建SubList时同样将modCount进行了复制,若在SubList中进行增加删除操作会更新modCount的值,但若在ArrayList中或其他线程中进行增加删除操作,修改了ArrayList中的modCount的值,则再次通过subList对List进行修改,则会抛出ConcurrentModificationException异常。
public void SublistTest(){
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<Integer> subList = (List<Integer>) list.subList(1, 2);
list.add(4);
//java.util.ConcurrentModificationException
subList.set(0, 1);
}
不管是通过iterator()或subList()修改ArrayList中的值,一旦拿到Iterator或SubList对象后,若通过其他方式修改ArrayList的值,均会抛出ConcurrentModificationException异常。