一、 ArrayList概述:
ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。
ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输, 实现了Cloneable接口,能被克隆。
1) 私有属性:
ArrayList定义只定义类两个私有属性:
ArrayList是基于数组实现的,是一个动态数组,如下:其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。
transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
有个关键字需要解释:transient。
Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。
为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
2)构造方法:构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
Collection解释:类集,是一组对象。类集的增加使得许多 java.util中的成员在结构和体系结构上发生根本的改变。它也扩展了包可以被应用的任务范围。(网上查的)
集合的构造方法和固定集合的大小
List arrayList = new ArrayList(4);
3) 调整数组容量ensureCapacity:
添加元素的时候会先判定集合的容量大小,是否需要扩容
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,
如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。
在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。
实例:
也就是说,当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。例如,默认的数组大小是10,也就是说当我们
add
10个元素之后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体情况如下所示:
总结:在用户向ArrayList追加对象时,Java总是要先计算容量(Capacity)是否适当,若容量不足则把原数组拷贝到以指定容量为长度创建的新数组内,并对原数组变量重新赋值,指向新数组。
在这同时,size进行自增1。在删除对象时,先使用拷贝方法把指定index后面的对象前移1位(如果 有的话),然后把空出来的位置置null,交给Junk收集器销毁,size自减1,即完成了。