JAVA 集合类(java.util)源码阅读笔记------ArrayList

时间:2022-03-13 17:01:11

一、继承关系

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

继承自AbstractList抽象类,实现List接口,RandomAccess接口,Cloneable接口, java.io.Serializable接口。

说明:
(1)RandomAccess:空接口,实现该接口代表该类拥有随机访问list对象的能力。
(2)Cloneable:空接口,实现该接口,重写Object的clone方法,否则会抛出异常。调用super.clone()实现对象的复制,如果对象中有引用,可以在super.clone后面进行处理。
(3)java.io.Serializable:空接口,实现该接口代表该类可序列化

类中的方法都是对List接口中方法的具体实现。

二、成员变量

private static final int DEFAULT_CAPACITY = 10;//默认的数组长度
transient Object[] elementData;//存储list中元素的数组,transient关键字表示该对象在ArrayList序列化时不被序列化。
private int size;//数组中实际元素的个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组的最大长度

三、重要方法说明

(1)clone: 保证复制ArrayList对象时,内部包含的elementData数组引用能重新申请空间创建数组,为深复制。
    public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
//保证该clone是深复制,不加这句话,则复制的ArrayList对象中elementData指向的还是原对象中的数组。
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}


(2)toArray:传入参数,将elementData中数据存入的数组。若该数组的长度<size,则重新返回一个复制了elementData数据的该类型数组;否则直接将elementData中元素向a中复制,同时将a[size()]置为空,返回a。
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}


(3)add:当数组长度不够时,需要动态扩容
    public boolean add(E e) {
ensureCapacityInternal(size + 1); // size为element数组的实际大小,若size+1<elementData.length,则不用动态扩容,否则需要将elementData进行动态扩容。
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);
}
grow:elementData数组扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//每次增长newCapacity=oldCapacity*1.5,为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果oldCapacity*1.5倍后,容量还是比minCapacity要小,则将newCapacity的值直接置为minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果增长的新长度大于了MAX_ARRAY_SIZE,则调用hugeCapacity来获取一个不大于Integer.MAX_VALUE的值。
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//重新申请一个newCapacity长度的数组空间,并把elementData数组中内容拷贝过去。
elementData = Arrays.copyOf(elementData, newCapacity);
}
hugeCapacity: elementData的最大容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//当最小保证的容量minCapacity比MAX_ARRAY_SIZE还大时,返回Integer.MAX_VALUE;否则直接返回MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}


(4) add:在指定位置add一个元素
    public void add(int index, E element) {
rangeCheckForAdd(index);

ensureCapacityInternal(size + 1); // 确保数组的长度>=size+1
//将elementData中index到数组最后一个元素,整体向后移动一个位置,空出index这一个位置,将element填入
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);

Object[] a = c.toArray();
int numNew = a.length;
//确保数组能容下添加的所有元素,可能进行动态扩容
ensureCapacityInternal(size + numNew); // Increments modCount

//计算从Index到处数组最后一个元素需要移动的元素的个数
int numMoved = size - index;
if (numMoved > 0)
//直接采用System.arraycopy将elementData数组中从index开始到最后一个元素位置这一段数据,移动到index+numNew位置
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//若index等于size,则直接在原数组后面添加
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}


(5)remove
//是一个前闭后开的区间,就是toIndex位置的元素不被移除,fromIndex位置元素被移除
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
//需要移动的元素的个数=toIndex到最后一个元素位置
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);

// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;//设置为null,让gc有机会回收
}
size = newSize;
}



(6)此外还提供了private void readObject(java.io.ObjectInputStream s)、 private void writeObject(java.io.ObjectOutputStream s)两个私有的序列化反序列化方法。


注意:
关于ArrayList中的Iterable(collection继承自此接口,所以collection的所有子类或者实现类都需要实现Iterator方法)接口中iterator()方法的实现
若一个线程在操作该ArrayList的iterator时,另一个线程对该ArrayList对象进行了添加修改删除更新操作,则会抛出new ConcurrentModificationException();
原因:http://www.cnblogs.com/skywang12345/p/3308762.html