Java 集合框架之 List 系列
ArrayList 学习总结 - 基于JDK1.8
ps:所有总结均是个人查看源码手写总结,未借鉴其他博客,转发请标明出处
ArrayList 继承关系图:
上级接口:List,Cloneable,RandomAccess,Serializable
上级抽象类:AbstractList
先说ArrayList的属性:
transient Object[] elementData:
ArrayList底层实现,Object数组, transient使其不参与序列化反序列化
int size: 记录数组的实际使用个数
int DEFAULT_CAPACITY = 10:默认初始容量,当调用无参构造方法后,使用add时方法会使用
需要区分以下两个数组的区别,在不同场景中使用不同
Object[] EMPTY_ELEMENTDATA = {}:
调用有参构造方法传0时,以及调用参数为Collection的构造方法,但该对象元素个数为0时,设置elementData为该空对象数组
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}:
调用无参构造方法时会设置elementData为该值
接下来说构造方法:
无参构造方法
public ArrayList() {
// 设置elementData为此空对象数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
设置ArrayList初始容量的构造方法
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 当参数大于0时直接创建对应大小的Object数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 将底层数组设置为此空对象数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 参数小于0时抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
传入Collection对象的有参构造方法,将该对象的元素添加到ArrayList中
public ArrayList(Collection<? extends E> c) {
// 将参数转为Object对象数组
Object[] a = c.toArray();
if ((size = a.length) != 0) {
// 参数元素不为0时如果参数是ArrayList对象则让elementData直接指向该对象数组
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
// 否则将该参数元素拷贝到elementData中
// Arrays.copyOf()也是使用了System.arraycopy(),后者为native方法
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// 当该参数元素为0时设置elementDat为此空对象数组
elementData = EMPTY_ELEMENTDATA;
}
}
add(E e)方法执行流程简述:
1.调用ensureCapacityInternal方法,将数组实际容量size + 1后传入该方法
2.调用calculateCapacity方法,计算需要的容量,如果之前构造函数是使用的无参构造,那么会返回DEFAULT_CAPACITY = 10,否则返回的就是之前的size + 1
3.调用ensureExplicitCapacity方法,参数为10 或者 size + 1
4.如果是之前调用的无参构造函数并返回10作为参数进行此方法调用时,必定会直接走到下一步-扩容
5.不然的话会判断size + 1与elementData数组大小,若容量不够,则调用grow进行扩容
6.若容量够,则会返回ensureCapacityInternal方法,执行赋值操作
7.容量不够时调用grow方法进行扩容
8.grow执行流程:按旧数组扩容1.5倍,调用Array.copyOf方法进行拷贝
9.执行elementData(size++) = e, 完成赋值
由于此处代码比较简单,就不上传源码了
add(int index, E element)方法执行流程简述:
在指定位置添加元素,与上一个方法不同之处1: 插入前要判断插入下标是否没有越界,2:扩容之后调用Sysetm.arraycopy方法进行数组拷贝
remove(Object o)方法简述
o为null时从0至size-1判断元素是否为null,遇到第一个null时删除该元素然后退出返回true,否则返回false,非null时则调用equals方法进行判断,后续操同null元素判断
iterator()和listIterator()
ArrayList本身也是实现了iterator方法的,实现原理和AbstractList类似,通过内部类。同时也实现了ListIterator方法,可以实现从后往前迭代ArrayList集合
总结: ArrayList底层实现实际是使用了对象数组,所以它是可以实现随机存取的,读取效率高,在指定位置插入和删除元素的效率低(因为需要挪动其他元素),非线程安全,是快速失败的,不可在循环中通过自身的remove方法删除元素,单线程情况下可以使用iterator对象的remove方法删除元素,多线程情况下则需要对迭代器加锁
推荐:: 使用stream流操作集合会使得代码量减少很多