ArrayList类重要方法源码解析:
ArrayList的继承与属性
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
//默认的容量大小
private static final int DEFAULT_CAPACITY = 10;
//空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList中实际存储元素的Object数组
transient Object[] elementData;
//ArrayList中实际包含的元素数量
private int size;
//最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2.三个构造方法
//带一个参数的构造方法:(初始化一个指定大小的数组)
public ArrayList(int initialCapacity) {
//创建长度为initialCapacity的数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
}//如果指定大小为0,创建一个空数组
else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
}
}
不带参数的构造函数:
public ArrayList() {
//默认构建一个空数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//参数为集合的构造函数:构建一个包含指定集合元素的列表
public ArrayList(Collection<? extends E> c) {
//将要构造的集合转为数组并且直接赋值给elementData
elementData = c.toArray();
//指定的集合中有元素
if ((size = elementData.length) != 0) {
// 当c.toArray出错,没有返回Object[]时,利用Arrays.copyOf 来复制集合c中的元素到elementData数组中
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//指定的集合中没有元素,用空数组代替
this.elementData = EMPTY_ELEMENTDATA;
}
}
3.常用方法——添加
//默认在末尾添加某个元素,返回值为是否添加成功
public boolean add(E e) {
//判断添加一个元素后是否需要扩容
ensureCapacityInternal(size + 1); elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//判断是否是第一次初始化数组
//判断当前数组是否 == EMPTY_ELEMENTDATA,因为默认构造函数创建时是将空数组EMPTY_ELEMENTDATA赋值给elementData
if (elementData == EMPTY_ELEMENTDATA) {
//判断默认容量10和当前数据长度的大小,取其中大的值作为判断本次是否需要扩容的依据,由于第一次数组是空的,所以默认要使数组扩容到10的长度
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//判断是否需要扩容
ensureExplicitCapacity(minCapacity);
}
//判断扩容的方法
private void ensureExplicitCapacity(int minCapacity) {
//如果需要扩容,modCount加1,该参数表示当前列表结构被修改的次数
modCount++;
//判断当前数据量是否大于数组长度
if (minCapacity - elementData.length > 0)
//如果大于则进行扩容操作
grow(minCapacity);
}
//扩容方法
private void grow(int minCapacity) {
// 记录扩容前的数组大小
int oldCapacity = elementData.length;
//新的容量等于原来容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果扩容后的长度<当前数据量,则将当前数据量作为本次扩容的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//判断扩容后的容量是否大于允许的最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果大于则将最大容量作为本次扩容的长度
newCapacity = hugeCapacity(minCapacity);
//将原来的值copy到新数组中去
elementData = Arrays.copyOf(elementData, newCapacity);
}
//判断新数组的长度是否超过了当前数组定义的最大长度,如果超过就将扩容长度设置为MAX_ARRAY_SIZE,也就是int的最大长度
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
//在指定位置添加元素
public void add(int index, E element) {
//判断下标是否越界,如果越界直接抛出异常
rangeCheckForAdd(index);
//判断添加该元素后是否需要扩容
ensureCapacityInternal(size + 1);
//将下标后面的数组全部后移一位
//elementData:源数组;index:源数组中的起始位置;elementData:目标数组;index + 1:目标数组中的起始位置; size - index:要复制的数组元素的数量;
System.arraycopy(elementData, index, elementData, index + 1, size - index);
//将元素插入当前下标的位置
elementData[index] = element;
//集合中元素个数值加1
size++;
}
3 常用方法—删除
//删除某个下标的元素,并返回该元素的下标值
public E remove(int index) {
//判断下标是否越界
rangeCheck(index);
//增加结构修改的次数
modCount++;
//获得指定下标的元素
E oldValue = elementData(index);
//计算出删除该元素后需要移动的数据长度(假如集合中有10个元素,删除下标为1的元素后,需要将后面的8个元素向前移1位)
int numMoved = size - index - 1;
//判断需要移动的数量是否>0
if (numMoved > 0)
//拷贝数组,重新赋值
System.arraycopy(elementData, index+1, elementData, index, numMoved);
//集合中元素个数减1,且将集合中最后一位置null
elementData[–size] = null; // clear to let GC do its work
//返回被移除的元素
return oldValue;
}
//删除该元素在数组中出现的第一个位置上的数据,如果该数据存在返回true,否则返回false
public boolean remove(Object o) {
//判断要删除的元素是否存在
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//如果要删除的元素不为null
for (int index = 0; index < size; index++)
//在数组中找到该元素
if (o.equals(elementData[index])) {
//删除该元素
fastRemove(index);
return true;
}
}
return false;
//直接删除该下标的值
private void fastRemove(int index) {
//数组结构修改次数增加1
modCount++;
//计算需要移动的数据个数
int numMoved = size - index - 1;
//如果需要移动的个数大于0
if (numMoved > 0)
//将该元素后面的数据往前移一位
System.arraycopy(elementData, index+1, elementData, index, numMoved);
//数组中元素个数减1且将最后一位设置为null,以方便GC回收
elementData[–size] = null; // clear to let GC do its work
}
//批量删除
//删除从某两个位置之间的元素
protected void removeRange(int fromIndex, int toIndex) {
//数组结构修改次数增加1
modCount++;
//计算删除这些元素需要移动的数据个数
int numMoved = size - toIndex;
//将截止位置之后的数据拷贝到开始删除位置及之后
System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
//计算删除这些元素后集合中的剩余数据长度
int newSize = size - (toIndex-fromIndex);
//将向前移动后置空的位置设为null,方便GC回收
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
//更新集合中实际元素的个数
size = newSize;
}
//删除指定集合中所有数据
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull©;
return batchRemove(c, false);
}
//批量移动
private boolean batchRemove(Collection<?> c, boolean complement) {
//将当前数组赋给新数组
final Object[] elementData = this.elementData;
//w表示批量删除后还剩多少元素
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
//如果要删除的集合中不包含原数组中的元素
if (c.contains(elementData[r]) == complement)
//将原数组中r位置的数据覆盖掉w位置的数据
elementData[w++] = elementData[r];
} finally {
//finally语句块是一定会执行的
//首先判断r是否等于size,不等于时假设此时ArrayList里面的size是10,r=3 ,这个System.arraycopy方法,先将batchRemove方法自己的elementData数组10个元素从r=3开始进行复制,然后添加进ArrayList自己的elementData数组中,并且从w开始的位置加入,加入的长度是size-r也就是7个长度。
if (r != size) {
System.arraycopy(elementData, r, elementData, w, size - r);
w += size - r;
}
if (w != size) {
//一个for循环,从w位置开始,一直遍历到size最后的位置,将w开始的元素以及之后的元素都设置成为null,然后重新设置size的长度为w,将后面所有的null都交给GC垃圾回收机制去处理。随后更改modified的值,表示ArrayList里面的数据确实发生了改动。
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
//将集合置空
public void clear() {
modCount++;
//将数组中所有元素全部设置为null,以方便GC回收
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
判断是否包含某个元素
public boolean contains(Object o) {
//如果该元素的下标值>0,说明该元素在数组中,返回true
return indexOf(o) >= 0;
}
根据指定的元素,判断它在数组中的位置,返回该元素的下标
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
//循环遍历数组,判断指定元素是否在数组中,存在则返回该元素的下标
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
//获取某元素在数组中最后出现的位置
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i–)
if (elementData[i]==null)
return i;
} else {
//从后往前遍历,找到第一个与该元素相等的值则返回其下标
for (int i = size-1; i >= 0; i–)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
查找—不改变数组结构,不修改modCount的值
获得某个下标的值
public E get(int index) {
//判断是否越界
rangeCheck(index);
//返回数组中该下标的元素的值
return elementData(index);
}
//将某个位置上的元素设置为指定的值
public E set(int index, E element) {
//判断是否越界
rangeCheck(index);
//将原来index位置上的元素值保存起来
E oldValue = elementData(index);
//将指定的值的放在index位置上
elementData[index] = element;
//返回原来的位置上的值
return oldValue;
}
迭代器
public ListIterator listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
public ListIterator listIterator() {
return new ListItr(0);
}
public Iterator iterator() {
return new Itr();
}
//Itr类继承了Iterator接口,重写了其方法
private class Itr implements Iterator {
//要返回的下一个元素的索引
int cursor; // index of next element to return
//返回的最后一个元素的索引;如果没有
int lastRet = -1; // index of last element returned; -1 if no such
//用来判断集合是否修改过结构的标志
int expectedModCount = modCount;
Itr() {}
//判断是否还有下一个元素
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继续指向下一个元素
cursor = i + 1;
//返回元素,并设置上一次返回元素的下标
return (E) elementData[lastRet = i];
}
//没有指定下标则删除最后一个位置的元素
public void remove() {
//如果没有最后一个元素,抛出异常
if (lastRet < 0)
throw new IllegalStateException();
//判断是否修改过结果,如果修改过直接抛出异常
checkForComodification();
try {
//删除lastRet位置的元素
ArrayList.this.remove(lastRet);
//将下一个元素的索引指向这个lastRet
cursor = lastRet;
//为了防止重复删除,将删除位置的lastRet索引设置为-1
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
参考博客:https://blog.csdn.net/opensuns/article/details/82777473
也有参考其他博客,视频,如有侵权,请告知以删除