ArrayList是常用的集合类,底层所使用的是数组。其特点相对数组来说可以动态扩充。
构造函数方法:
List<T> list = new ArrayList<>();
List<E> list2 = new ArrayList<>(16);
//常量,一个空的Object数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//指向数据数组的引用
transient Object[] elementData;
//常量,一个空的Object数组,它与DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是有区别的,后面可以看到
private static final Object[] EMPTY_ELEMENTDATA = {};
//无参构造方法
public ArrayList() {
//初始大小为空
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//有初始大小的构造方法
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//按照对应初始值,分配数组空间
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//初始大小为空
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
添加:
boolean add(E e):
//ArrayList包含元素的数量
private int size;
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//容器修改次数,主要用于迭代过程中的快速失败,后面会看到
protected transient int modCount = 0;
//最大数组长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public boolean add(E e) {
//【重点】: 判断是否需要扩容,如果需要,根据特定的算法确定扩容大小
ensureCapacityInternal(size + 1); // Increments modCount!!
//向后追加数据
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//数组为空的两种情况:(1).new ArrayList() ; (2).new ArrayList(0);
//第一次添加元素时,如果是(1):elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA
//如果是(2):elementData==EMPTY_ELEMENTDATA
//在第一次添加元素时,(1)的情况下,ArrayList的容量从0增加到>=10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//确定ArrayList的容量
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//修改次数加1
modCount++;
//判断是否需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
//原始容量
int oldCapacity = elementData.length;
//在原始容量的基础扩充50%
int newCapacity = oldCapacity + (oldCapacity >> 1);
//选取minCapacity 和 newCapacity 中的最大值,作为newCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果在原始容量的基础扩充50%,超出了数组的最大长度,则需要根据minCapcity重写计算
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//创建新的数组对象,同时拷贝原数组中的数据
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;
}
疑问:根据代码来看,ArrayList的最大长度MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,最终扩展还是可以到Integer.MAX_VALUE,这样有什么考究吗?如果有大佬知道,请留言,感谢!
删除:
boolean remove(int index):
//根据下标删除元素
public E remove(int index) {
//检查下标是否合法
rangeCheck(index);
//修改次数加1
modCount++;
//找出对应元素
E oldValue = elementData(index);
//计算所需移动元素的个数
int numMoved = size - index - 1;
//将index+1到size中的元素左移一位
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//清除最后一个元素的数据,
//如果最后一个元素是引用类型,可以让GC回收
elementData[--size] = null;
//返回移除元素
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
boolean remove(Object o):
public boolean remove(Object o) {
if (o == null) {
//移除空元素
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//移除非空元素
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
//与上面的移除方法类似
private void fastRemove(int index) {
modCount++;
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
}
迭代器:
Iterator<E> iterator():
public Iterator<E> iterator() {
return new Itr();
}
//迭代器具体实现
private class Itr implements Iterator<E> {
//下一个元素的下标
int cursor;
//最后一个返回元素的下标值
int lastRet = -1;
//保存再遍历之前ArrayList的修改次数
//说明:ArrayList在迭代时,不允许其他线程向集合中添加或删除元素
int expectedModCount = modCount;
//下一个元素下标<size
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
//检查在遍历过程中是否有其他线程删除或添加元素
checkForComodification();
int i = cursor;
//下标已经超出范围
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
//判断是否有其他线程并发删除了集合中的元素
if (i >= elementData.length)
throw new ConcurrentModificationException();
//指向下一个元素
cursor = i + 1;
//取出元素值,同时给lastRet赋值
return (E) elementData[lastRet = i];
}
//删除最近一个迭代元素
public void remove() {
//元素还未迭代,无法删除
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
//删除最近一个迭代元素
ArrayList.this.remove(lastRet);
//删除后从lastRet+1到size-1的元素向前移动一位
//所以下一个元素下标还是lastRet
cursor = lastRet;
lastRet = -1;
//当前线程可以删除元素,这里赋值就是避免checkForComodification()检查出错
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//java8中提供的,用于对剩余未迭代元素进行处理,处理方式由调用者定制
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
//下一个元素,也就是未处理的第一个元素
int i = cursor;
//判断是否有剩余元素处理
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
//检查并发问题
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
//遍历剩余元素,用定制的方法处理
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
//更新相关数据
cursor = i;
lastRet = i - 1;
checkForComodification();
}
//检查是否有并发问题
final void checkForComodification() {
//迭代过程中不允许其他线程修改或删除元素
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
ListIterator<E> listIterator(int index):
//ListItr 对Itr迭代器进行扩展,Itr中只有删除元素的方法,这里扩展了‘添加/替换’元素的方法
//并且可以指定迭代位置,以及迭代方向,支持向前迭代
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
//继承Itr迭代器
private class ListItr extends Itr implements ListIterator<E> {
//指定迭代位置
ListItr(int index) {
super();
cursor = index;
}
//判断是否可以向前迭代
public boolean hasPrevious() {
return cursor != 0;
}
//向后迭代的下一元素下标
public int nextIndex() {
return cursor;
}
//向前迭代的下一个元素下标
public int previousIndex() {
return cursor - 1;
}
//向前迭代的方法
@SuppressWarnings("unchecked")
public E previous() {
//检查并发问题
checkForComodification();
//前一个元素下标
int i = cursor - 1;
if (i < 0)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//cursor向前移动
cursor = i;
return (E) elementData[lastRet = i];
}
//替换掉最后一个已经迭代的元素值
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.set(lastRet, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
//添加到下一个遍历元素的位置,
//向前迭代:新添加的元素属于未迭代元素
//向后迭代:新添加的元素属于已迭代元素
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
//下一个迭代元素是新添加元素的前一个位置
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
暂时只分析到这,可以看到ArrayList的强大,远不止我们平常所看到的那些。