ArrayList类
ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List)
实现的接口和继承的类
函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类,它的容量是自动增长的。ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问(比使用迭代器访问更快),该接口只是一个标记接口,也无法强制用户做什么,实现了Cloneable接口,能被克隆。它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作
ArrayList定义类中俩个重要属性
继承的父类AbstractList有个重要的属性protected transient int modCount = 0;从结构上修改 、此列表的次数。从结构上修改是指更改列表的大小,或者打乱列表,从而使正在进行的迭代产生错误的结果。
在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列表元素数量发生改变)了,主要在多线程环境下需要使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。
transient Object[] elementData; // non-private to simplify nested class access
private int size;
elementData保存容器的元素,size指容器中元素的个数。
三种构造方法
//用户定义了初始大小为initialCapacity的构造方法
public ArrayList(int initialCapacity) {}
//无参的构造方法,默认容量是10
public ArrayList() {}
//初始化一个包含集合c的容器,大小也等于c的大小
public ArrayList(Collection
元素存储
ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
每次添加元素都要检查容器大小是否足够,如果元素数组是空,则容器为默认大小10,如果且容器大小不够,则把容器大小增加为原来的1.5倍,如果还是不够,新容器大小为新加上进来元素或者集合的大小.
这里有个问题hugeCapacity(int minCapacity);MAX_ARRAY_SIZE比Integer.MAX_VALUE小8.文档解释是一些虚拟机在数组中保留了一些头字节,分配更多的空间可能导致内存溢出。也有解释是数组自己用了8个字节存储大小2,147,483,648,所以存储容量为2的31次方-8.
元素读取
// 返回此列表中指定位置上的元素。
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
元素删除
// 移除此列表中指定位置上的元素。返回移除的元素
public E remove(int index) { }
// 移除此列表中首次出现的指定元素(如果存在)。这是因为ArrayList中允许存放重复的元素。
public boolean remove(Object o) { }
总结
当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。