目录
构造方法
ArrayList共有三种构造方法:
1. 无参构造
创建一个长度10的Object数组。
2.参数是int型 [0~2^31-1)
若参数大于0,创建指定长度的Object[];
若参数等于0,Object类型的空数组;
其他情况,抛出异常。
3.参数是Collectinon
创建一个包含集合c所有元素的List,元素集合和集合Iterator遍历得到的元素顺序一样。
void trimToSize()
若List中元素个数小于List长度,进行判断:
元素个数为0,trim后返回空Object数组;
否则的话通过Arrays.copyOf(Object [], int size)
进行trim。
扩容函数
//以下是ArrayList的部分源码
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return 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);
}
void grow(int minCapacity)
ArrayList扩容的核心函数。每次扩容后至少是原容量的1.5倍,若1.5倍容量仍不够,那么newCapacity直接设为minCapacity。最后如果newCapacity > MaxArrraySize 的话,使用hugeCapacity(int )比较minCapacity和MAX_ARRAY_SIZE的大小,如果前者大,那么新容量就是Integer.Max_Value,否则就是MAX_ARRAY_SIZE。
也就是说:ArrayList并非是无限大的,它最大可以扩容到2^31-1。
**注:**MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,这里减8的原因是需要8bit存储元信息。
boolean add(E e)
添加时先调用ensureCapacityInternal(int minCapacity)
方法把数组容量增加1;
然后将待添加的元素加入。
ensureCapacityInternal(int minCapacity)
该函数调用利用ensureExplicitCapacity()函数得到最小扩容量。
calculateCapacity()
calculateCapacity(Object[] elementData, int minCapacity)
计算最小空间:
若elementData为空,那么返回max(10, minCapacity);否则返回minCapacity。
remove函数
删除的时间复杂度为 O(N)。
public E remove(int index) {
rangeCheck(index);//检查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
//都向前移一位,所以最后以为置为null并将size-1
return oldValue;
}
fastRemove (int index)
用于remove(Obj o),较于remove(int index)只少了对index合法性的检测,以及不返回被删除的元素。
序列化
ArrayList 基于数组实现,并且具有动态扩容特性,因此保存元素的数组不一定都会被使用,那么就没必要全部进行序列化。
保存元素的数组 elementData 使用 transient 修饰,该关键字声明数组默认不会被序列化。
序列化时需要使用 ObjectOutputStream 的 writeObject() 将对象转换为字节流并输出。而 writeObject() 方法在传入的对象存在 writeObject() 的时候会去反射调用该对象的 writeObject() 来实现序列化。反序列化使用的是 ObjectInputStream 的 readObject() 方法,原理类似。
Fail-Fast
modCount 用来记录 ArrayList 结构发生变化的次数。结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。
在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException。