package com.alphamall.collection.list;
import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
public class LYHArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
//默认初始化的容量
private static final int DEFAULT_CAPACITY = 10;
//空元素数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认大小的空实例数组,在第一次调用 ensureCapacityInternal 时会初始化长度为10
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存放元素的数组
Object[] elementData;
//集合大小, 初始值为0
private int size;
/**
* Constructs an empty list with the specified initial capacity.
* 构造一个具有指定初始容量的空列表
*
* @param initialCapacity 列表的初始容量
* @throws IllegalArgumentException 如果指定的初始容量为负, 抛异常
*/
public LYHArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//如果指定的初始容量大于0, 则新new一个object数组
// 例如 initialCapacity==3, 则 elementData == [null, null, null]
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果等于0, 就让elementData=空数组;
this.elementData = EMPTY_ELEMENTDATA;
} else {
//否则抛出异常
throw new IllegalArgumentException("非法的容量异常: " + initialCapacity);
}
}
/**
* 构造一个初始容量为10的空列表
*/
public LYHArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 传入一个集合, 将这个集合中的数据放到elementData中
*/
public LYHArrayList(Collection<? extends E> c) {
//调用该集合的toArray方法, 将数据放入elementData数组中
elementData = c.toArray();
//如果此时elementData长度 != 0
if ((size = elementData.length) != 0) {
//如果传入的集合c可能不是对象类型的数组, 比如说List<String> list 字符串类型的
if (elementData.getClass() != Object[].class) {
//复制一个Object[]类型的数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
} else {
//如果传入的集合是空的, 就直接让 elementData = 空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 将ArrayList实例的容量调整为列表的当前大小, 使用此操作可以最小化ArrayList实例的存储
*/
public void trimToSize() {
//修改列表大小的次数 +1
modCount++;
//如果集合的大小 < 元素数组的长度
if (size < elementData.length) {
if (size == 0) {
//elementData = []空数组
elementData = EMPTY_ELEMENTDATA;
} else {
elementData = Arrays.copyOf(elementData, size);
}
}
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
//如果Object参数的是null, 则找到elementData中包含 null元素的下标
for (int i = 0; i < size; i++) {
if (elementData[i] == null) {
return i;
}
}
} else {
//否则比较每一个元素和Object参数是否相等, 相等则返回下标
for (int i = 0; i < size; i++) {
if (o.equals(elementData[i])) {
return i;
}
}
}
//没有则返回-1
return -1;
}
public Object clone() {
try {
LYHArrayList<?> v = (LYHArrayList<?>) super.clone();
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);
}
}
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
E elementData(int index) {
//返回elementData的元素, 并强转为指定类型
return (E) elementData[index];
}
@Override
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;
}
/**
* 将指定的元素追加到列表的末尾, 即elementData[size]的位置
*/
public boolean add(E e) {
//确定是否需要扩容
ensureCapacityInternal(size + 1); //增加 modCount修改次数的大小
//将元素e 赋值给 elementData[size], 然后size自增
// 这里如果是多线程的情况下会不安全, 假设 t1和 t2线程都执行到这一步, 会给 elementData[size]赋值,
// 然后size再++, 相当于只新增了一个元素
// 例如 elementData == [1,2,3,null], 此时size=3, t1线程给elementData[3]赋值 4, 但size还没来得及自增
// t2线程又给 elementData[3]的位置 赋值5, 最后就可能会导致, elementData == [1,2,3,5], 4没有加上
// 但 size却 ++ 2次, 即size==5
elementData[size++] = e;
return true;
}
/**
* 在列表的指定位置插入指定的元素。将当前在该位置的元素(如果有的话)和任何后续元素向右移动(在它们的下标上加1)
* 例如: elementData == [1,2,3,4,5,6,7,8,null,null] (elementData.length==10) 插入数字100以后 --->
* elementData == [1,2,3,4,100,5,6,7,8,null,null,null,null,null,null] 会伴随着扩容 (elementData.length==15)
* @param index 下标
* @param element 要新增的元素
*/
public void add(int index, E element) {
//判断index是否越界
rangeCheckForAdd(index);
//判断是否需要扩容
ensureCapacityInternal(size + 1);
/**
* 把数组的中间某一段, 复制到数组的另一段上
* 例如: [1, 2, 3, 4, 5, null, null] 中间的 [3,4,5] 复制到 [4,5,null] 的位置 ===> [1,2,3,3,4,5,null]
* @param src 原数组
* @param srcPos 要复制的某一段的起始位置
* @param dest 目标数组
* @param destPos 复制到目标位置
* @param length 要复制的数组长度
*/
System.arraycopy(elementData, index, elementData, index + 1, size - index);
//给index位置赋值 element
elementData[index] = element;
size++;
}
/**
* 移除列表中指定位置的元素。将所有后续元素向左移动(从其下标中减去1)
*/
public E remove(int index) {
//判断index是否越界, 即须要 index < size
rangeCheck(index);
modCount++;
//获取指定位置的元素
E oldValue = this.elementData(index);
//例如 elementData == [1,2,3,4,5] index==2 --> numMoved==2
int numMoved = size - index - 1; //numMoved: 要移动元素的数量
if (numMoved > 0) {
//elementData从 elementData[3]这个位置开始复制, 复制2个元素, 到elementData[2]这个位置
// 即 elementData == [1,2,3,4,5] --> elementData == [1,2,4,5,5]
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
//先让 size-1 == 4, 再让elementData[4] == null, elementData == [1,2,4,5,null]
elementData[--size] = null;
//返回被移除的元素
return oldValue;
}
/**
* 从列表中删除指定元素的第一个出现项(如果它存在的话)
* @param o
* @return
*/
public boolean remove(Object o) {
//先判断参数 o 是否为空
if (o == null) {
for (int i = 0; i < size; i++) {
if (elementData[i] == null) {
//移除第一次出现的空元素
fastRemove(i);
return true;
}
}
} else {
for (int i = 0; i < size; i++) {
if (o.equals(elementData[i])) {
//移除第一次出现的值相等元素
fastRemove(i);
return true;
}
}
}
return false;
}
/**
* 和 remove(int index) 方法类似
*/
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;
}
/**
* 从列表中删除所有元素。此调用返回后,列表将为空
*/
public void clear() {
modCount++;
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
/**
* 将指定集合中的所有元素追加到列表的末尾
* 例如: c==[6,7,8] length==3 elementData==[1,2,3,4,5,null] elementData.length==6
*/
public boolean addAll(Collection<? extends E> c) {
// objects==[6,7,8]
Object[] objects = c.toArray();
int length = objects.length;
//扩容 --> elementData==[1,2,3,4,5,null,null,null,null] elementData.length==6+3==9
ensureCapacityInternal(size + length);
//将[6,7,8]复制到 elementData[5]后面, 以index==5为起点 ---> elementData==[1,2,3,4,5,6,7,8,null]
System.arraycopy(objects, 0, elementData, size, length);
//这个时候 size==8
size += length;
return length != 0;
}
/**
* 从指定位置开始,将指定集合中的所有元素插入到此列表中
* 例如: c==[6,7,8] index=2 elementData==[1,2,3,4,5,null]
*/
public boolean addAll(int index, Collection<? extends E> c) {
//先检查 index 是否在 (0,size)这个区间中
rangeCheckForAdd(index);
// >>> objects==[6,7,8]
Object[] objects = c.toArray();
int length = objects.length;
//扩容 >>> elementData==[1,2,3,4,5,null,null,null,null] elementData.length==9
ensureCapacityInternal(size + length);
// 要移动的元素个数: 设最后一个元素的下标为 last, 从index下标开始,
// 则移动的元素个数为 last-index+1 == (last+1)-index == size-index
// >>> numMoved==5-2==3
int numMoved = size - index;
/*这里如果index==size, 那 numMoved==0, 就直接把 objects拼接到 size后面, 以size为起点*/
if (numMoved > 0) {
//从3复制到6的位置 >>> elementData==[1,2,null,null,null,3,4,5]
System.arraycopy(elementData, index, elementData, index + length, numMoved);
}
//再将 objects复制到3的位置 >>> elementData==[1,2,6,7,8,3,4,5]
System.arraycopy(objects, 0, elementData, index, length);
return true;
}
/**
* 从该列表中移除包含在指定集合中的所有元素
*/
public boolean removeAll(Collection<?> c) {
//检查指定的对象引用不是null
Objects.requireNonNull(c);
return batchRemove(c, false);
}
/**
* 从这个列表中删除指定集合中不包含的所有元素
*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
/**
* 批量移动, 把参数集合中不包含或包含的元素, 移动到数组前面
* 例如: elementData==[1,2,3,4,5,6,7] c==[1,3,6] complement==false
* >>> 移动后: elementData==[2,4,5,7,5,6,7]
*/
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++) {
//判断c中是否包含elementData 的第r个元素, 不包含就把当前元素放到前面, w每次+1
if (c.contains(elementData[r]) == complement) {
// r==0 elementData==[1,2,3,4,5,6,7] w==0
// r==1 elementData==[2,2,3,4,5,6,7] w==1
// r==2 elementData==[2,2,3,4,5,6,7] w==1
// r==3 elementData==[2,4,3,4,5,6,7] w==2
// r==4 elementData==[2,4,5,4,5,6,7] w==3
// r==5 elementData==[2,4,5,4,5,6,7] w==3
// r==6 elementData==[2,4,5,7,5,6,7] w==4
elementData[w++] = elementData[r];
}
}
} finally {
//r==7 size==7
if (r != size) {
System.arraycopy(elementData, r, elementData, w, size - r);
w += size - r;
}
//这一步就是将 elementData向前移动的元素保留下来, 其他的置为空
if (w != size) { //w==4
//elementData==[2,4,5,7,null,null,null]
for (int i = w; i < size; i++) {
elementData[i] = null;
}
// modCount += 7-4==3
modCount += size - w;
size = w; //size==4
modified = true;
}
}
return modified;
}
/**
* 遍历集合
*/
@Override
public void forEach(Consumer<? super E> action) {
//action不为空
Objects.requireNonNull(action);
final int expectedModCount = modCount;
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
// elementData[i]作为参数, 执行 action方法, 也就是自己的lambda表达式
for (int i = 0; i < size && modCount == expectedModCount; i++) {
action.accept(elementData[i]);
}
//在遍历的时候, arrayList中途不能修改
if (modCount != expectedModCount) {
throw new ConcurrentModificationException("并发修改异常");
}
}
/**
* 对每一个参数进行修改或替换操作
* arrayList==[1, 2, 3, 4, 5, 6, 7]
* arrayList.replaceAll(s -> {
* Integer integer = Integer.valueOf(s);
* return integer + 1 + "";
* });
* >>> arrayList==[1, 2, 3, 4, 5, 6, 7, 8]
* @param operator
*/
@Override
public void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i = 0; i < size && modCount == expectedModCount; i++) {
//对每个元素进行一元运算操作, 返回的是和参数相同的类型
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
/**
* 给list按照Comparator指定的规则排序
* @param c
*/
@Override
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
//根据指定比较器产生的顺序,对指定对象数组的指定范围进行排序
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
/**
* 删除该集合中满足给定断言条件的所有元素
* 例如 arrayList==[1, 2, 3, 4, 5, 6, 7] filter: s -> Integer.parseInt(s) > 3
* 删除比3大的所有元素
*/
@Override
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
int removeCount = 0;
final BitSet removeSet = new BitSet(size); // removeSet=={}
final int expectedModCount = modCount;
final int size = this.size; //size==7
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if (filter.test(element)) {
removeSet.set(i); //满足条件的元素下标放入 removeSet=={3,4,5,6}
removeCount++; //removeCount==4 要删除的元素数量是4个
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
final boolean anyToRemove = removeCount > 0; //removeCount==4
if (anyToRemove) {
final int newSize = size - removeCount; //size==7 removeCount==4 newSize==3
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
// >>>> 真正删除是从这一步开始的
// elementData==[1, 2, 3, 4, 5, 6, 7] >>> elementData==[1,2,3,null,null,null.null]
for (int k=newSize; k < size; k++) {
elementData[k] = null; //将下标从3到6的位置的元素为null
}
this.size = newSize; //size==3
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
/**
* 确定容量大小, 是否需要扩容
* ===> 一般,初始化 new ArrayList<>();没有指定容量, 第一次add就会扩容到10
* @param minCapacity 最小容量
*/
private void ensureCapacityInternal(int minCapacity) {
//如果elementData == [], 即 new ArrayList<>()的时候, 没指定初始容量 initialCapacity, 会让 minCapacity = 10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//获取 (size+1) 和 10的较大者, 这里elementData是等于空数组了, 那size+1等于1是肯定比 10 要小的,
//为什么还要获取两者之间的最大值呢? 直接把 10 赋给 minCapacity不行吗 ???
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
/**
* 判断elementData是否已经装满了, 就是判断需要的容量 是否大于 elementData的长度
* 例如: elementData == [1,2,3,null],add一个元素,就不需要扩容, 如果elementData == [1,2,3,4], 就需要扩容
*/
private void ensureExplicitCapacity(int minCapacity) {
//修改次数+1
modCount++;
//在add的时候, 判断时候需要扩容, 如果需要的最小容量即 (size+1) > elementData长度
if (minCapacity - elementData.length > 0) {
//例如list初始化指定的initialCapacity是3 【调用的是构造方法 public LYHArrayList(int initialCapacity)】
//此时elementData = new Object[3], elementData.length == 3; 也就是[null, null, null],
//在每次add元素的时候, 前三次走到这里判断 (size+1) 都是 <= 3的, 也就是不需要扩容, 当第四次add元素的时候,
//判断 size+1 == 4, 此时 4 > 3, 就走 grow 进行扩容
grow(minCapacity);
}
}
//数组允许的最大长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 增加容量,以确保它至少能容纳由最小容量参数指定的元素数量
* @param minCapacity 期望的最小容量
*/
private void grow(int minCapacity) {
//获取旧容量
int oldCapacity = elementData.length;
//new = old + old/2, 扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量 < 最小容量
if (newCapacity - minCapacity < 0) {
// 能走到这里, 有两种情况
// 1. elementData等于空数组[], 此时 minCapacity = DEFAULT_CAPACITY==10
// oldCapacity==0 --> newCapacity==0 --> 0<10 则让 newCapacity = minCapacity==10
// 2. 可能是一开始构造方法指定 initialCapacity==1
// 比如 elementData == [1], elementData.length==1 --> oldCapacity==1 --> newCapacity==1,
// 而此时 minCapacity == size+1 == 2, minCapacity(2) > newCapacity(1), newCapacity会重新赋值为 2
newCapacity = minCapacity;
}
//新容量 > 最大数组容量
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
//elementData复制新容量的数组, 再赋值给 elementData (例如[1,2,3] ===> [1,2,3,null])
elementData = Arrays.copyOf(elementData, newCapacity);
}
//最大的容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
//如果最小容量 > Integer.MAX_VALUE - 8
if (minCapacity > MAX_ARRAY_SIZE) {
//返回 2的31次方 -1
return Integer.MAX_VALUE;
} else {
//返回 2的31次方 -9
return MAX_ARRAY_SIZE;
}
}
/**
* 判断 index是否越界, 必须 0 <= index <= size
* ===> 给 add and addAll 使用的方法
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 检查给定的索引是否在范围内。如果不是,则抛出适当的运行时异常。
* 此方法不检查索引是否为负:它总是在数组访问之前立即使用,如果索引为负,将抛出ArrayIndexOutOfBoundsException
*/
private void rangeCheck(int index) {
if (index >= size) {
//下标越界异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
}
ArrayList源码分析
最新推荐文章于 2024-08-14 23:12:09 发布