Java集合深入学习 - ArrayList源码解析-1基础(基于jdk1.8)
Java集合深入学习 - ArrayList源码解析-2序列化与迭代器(基于jdk1.8)
Java集合深入学习 - ArrayList源码解析-3子List与坑点(基于jdk1.8)
话不多说,直接上代码
/**
* ArrayList 类定义
* 继承:AbstractList(抽象List)
* 实现:List,RandomAccess(支持快速随机访问标记),Cloneable(克隆),Serializable(序列化)
*/
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable{}
/**
* AbstractList类的定义 (抽象类)
* 继承:AbstractCollection(抽象集合)
* 实现:List
*/
public abstract class AbstractList extends AbstractCollection implements List{}
/**
* AbstractCollection类定义(抽象类)
* 实现:Collection(集合接口)
*/
public abstract class AbstractCollection implements Collection{}
/**
* Collection类定义(接口)
* 继承:Iterable(迭代器接口)
*/
public interface Collection extends Iterable {}
/**
* Iterable类定义(接口)
*/
public interface Iterable{}
/**
* List类定义(接口)
* 继承:Collection(集合接口)
*/
public interface List extends Collection{}
对应类关系如下图:
话不多说,直接代码中注释起来
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable{
private static final long serialVersionUID = 8683452581122892189L;
/** 默认的初始容量为10 */
private static final int DEFAULT_CAPACITY = 10;
/** 两个final的空数组 */
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/** 存放数据的数组 */
transient Object[] elementData;
/** 实际存放数据数量(并不是数组的大小) */
private int size;
/** 定义一个常量,含义为集合大小的最大值 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 初始化容量的构造方法
* initialCapacity对应存放数据的数组的大小
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//传入大小,直接初始化一个对应大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//传入参数0 先默认数组为空数组,在第一次add的时候会初始化数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
//传入为负数时直接抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 空参构造方法
*/
public ArrayList() {
//默认数组为空数组,在第一次add的时候会初始化数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 给定集合入参的构造方法
* 知识点: 1. String[].getClass() != Object[].class;
* 2.子类重写父类方法的时候,若不修改返回值类型,则具体得到返回值的类型的是子类的返回值类型,而不会上转成父类的返回值类型
*/
public ArrayList(Collection extends E> c) {
//直接获取集合中的数组(集合中的数据)
elementData = c.toArray();
//判断是否存在数据
if ((size = elementData.length) != 0) {
//判断数据类型是否一致(传入集合的toArray方法可能被重写导致下面判断不成立)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//无数据,数组置空
this.elementData = EMPTY_ELEMENTDATA;
}
}
}
/** 父类属性 */
public abstract class AbstractList extends AbstractCollection implements List {
/**
* 操作次数:指的是改变了list的长度大小或者使得遍历过程中产生不正确的结果的操作
* 作用:在Iterator对数据进行迭代时用来判断数据是否发生了意外变化,导致最后遍历会失败
*/
protected transient int modCount = 0;
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 添加数据
*/
public boolean add(E e) {
//数组大小处理
ensureCapacityInternal(size + 1);
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++; //操作次数+1
if (minCapacity - elementData.length > 0) //判断是否需要对数组进行扩容
grow(minCapacity); //扩容
}
/**
* 对集合进行扩容
*/
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //newCapacity = 1.5 * oldCapacity 扩容到原大小的1.5倍
//获取合适的大小
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); //数据copy,返回一个新的数组
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
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);
//数据后移(将从index位置开始往后数据都往后移动一位)
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element; //插入数据
size++;
}
/**
* 下标校验,判断下标是否超出大小
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
/**
* 添加集合中的全部数据到List中
*/
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray(); //获取数据
int numNew = a.length; //待添加数据数
ensureCapacityInternal(size + numNew); //本地数组大小处理
System.arraycopy(a, 0, elementData, size, numNew); //将获取到的数据添加到数组中
size += numNew; //集合size增加
return numNew != 0; //返回实际是否成功添加数据
}
/**
* 将集合数据插入的List中(从指定下标开始插入)
*/
public boolean addAll(int index, Collection extends E> c) {
rangeCheckForAdd(index); //下标校验
Object[] a = c.toArray(); //获取待插入数据
int numNew = a.length; //待插入数据数
ensureCapacityInternal(size + numNew); //处理数组大小
int numMoved = size - index; //计算需要移动的数据大小
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved); //插入位置之后的数据整体向后移动numNew位
System.arraycopy(a, 0, elementData, index, numNew); //将数据从index位置开始插入到数组中
size += numNew; //集合size增加
return numNew != 0;//返回实际是否成功添加数据
}
/**
* 下标校验,判断下标是否超出大小
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
/**
* 移除指定下标数据,返回被移除数据
*/
public E remove(int index) {
rangeCheck(index); //下标校验
modCount++; //操作次数+1
E oldValue = elementData(index); //获取待移除数据
int numMoved = size - index - 1; //计算需要移动的数据数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //后边数据整体向前移动1位
elementData[--size] = null; //最后一位置空
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 移除指定数据(移除第一个) 返回操作是否成功,未找到对应数据返回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 {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false; //未找到对应数据返回false
}
/**
* 移除指定下表数据
*/
private void fastRemove(int index) {
modCount++; //操作次数+1
int numMoved = size - index - 1; //计算需要移动的数据数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //后边数据整体向前移动1位
elementData[--size] = null; //最后一位置空
}
/**
* 移除指定集合中的所有数据
*/
public boolean removeAll(Collection> c) {
Objects.requireNonNull(c); //非空校验
return batchRemove(c, false);
}
/**
* 移除除集合中数据之外的所有数据
*/
public boolean retainAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
private boolean batchRemove(Collection> c, boolean complement) {
final Object[] elementData = this.elementData; //获取List数据
int r = 0, w = 0;
boolean modified = false; //是否成功移除数据
try {
for (; r < size; r++) //遍历数据
if (c.contains(elementData[r]) == complement) //判断当前数据是否在指定集合中 是否符合条件complement
elementData[w++] = elementData[r]; //将满足条件的数据按顺序放到数组的前面
} finally {
if (r != size) { //发现异常会进入到此条件
System.arraycopy(elementData, r,
elementData, w,
size - r); //将还未处理数据直接放到最终数组之后
w += size - r; //计算满足条件数据大小
}
if (w != size) { //判断是否有不满足条件数据 存在不满足条件数据时会进入此条件
for (int i = w; i < size; i++) //清空数组后面的无用数据(满足条件数据都已放到数组的前面,w之后的数据都是无用数据)
elementData[i] = null;
modCount += size - w;
size = w; //重新计算大小
modified = true; //标记有数据被处理掉
}
}
return modified; //返回是否有数据被处理掉
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
/**
* 获取指定下标数据
*/
public E get(int index) {
rangeCheck(index); //下标校验
return elementData(index); //返回数据
}
/**
* 修改数据并返回原数据
*/
public E set(int index, E element) {
rangeCheck(index); //下标校验
E oldValue = elementData(index); //获取源
elementData[index] = element; //修改数据
return oldValue; //返回源数据
}
/**
* 获取数据在集合里的下标(数据在集合中第一次出现)
* 存在返回对应下标,不存在返回-1
*/
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;
}
/**
* 获取数据在集合里的下标(数据在集合中最后一次出现)
* 存在返回对应下标,不存在返回-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;
}
/**
* 集合是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 集合中是否包含这个数据
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* 将数组的大小设置为当前集合的大小(完成操作之后 数组大小=集合大小)
*/
public void trimToSize() {
modCount++; //操作次数加一
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA //size为0 数组置为空
: Arrays.copyOf(elementData, size); //获取数组的前size个数据,返回一个新的数组
}
}
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
/**
* 集合克隆,复制出一个新的集合与该集合数据完全一致,集合中数组大小为数据量大小
*/
public Object clone() {
try {
ArrayList> v = (ArrayList>) 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);
}
}
/**
* 将集合转换成数组,数组的大小为集合数据量大小
* 返回一个新的Object[]
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
/**
* 将集合转换成数组,数组的大小为集合数据量大小
* 返回传入的数组
*/
@SuppressWarnings("unchecked")
public 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;
}
本文连接,转载请标注https://blog.csdn.net/luo_mu_hpu/article/details/106076965