ArrayList源码总结基于jdk_8,如有错误欢迎指正
1. 类的继承关系
ArrayList类继承自AbstractList类,实现了List接口
2. 变量及其含义
变量名 | 修饰符 | 类型 | 默认值 | 含义 |
---|---|---|---|---|
serialVersionUID | private static final | long | 8683452581122892189L | 利用该值验证序列化版本的一致性 |
DEFAULT_CAPACITY | private static final | int | 10 | 初始化的ArrayList大小 |
EMPTY_ELEMENTDATA | private static final | Object[] | {} | 有参构造,但传入的initialCapacity为0时,elementData默认值 |
DEFAULTCAPACITY_EMPTY_ELEMENTDATA | private static final | Object[] | {} | 无参构造elementData默认值 |
elementData | transient | Object[] | 无 | 存储ArrayList内容的缓冲区数组ArrayList的本质就是在维护一个Object数组 |
size | private | int | 无 | ArrayList的长度 |
MAX_ARRAY_SIZE | private static final | int | Integer.MAX_VALUE - 8 | ArrayList的最大容量 |
------- | ------- | ---- | ------- | ----- |
modCount(父类AbstractList中的全局变量) | protected transient | int | 0 | 记录list大小改变的次数 |
3. 构造函数
3.1. 有参构造
1. 变量初始化方式
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);
}
}
- 有参构造流程
2. 集合初始化方式
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
-
指定初始数据初始化时,会有这样的注释“ see 6260652”,这是 Java 的一个 bug,意思是当给定集合内的元素不是
Object 类型时,会转化成 Object 的类型。一般情况下都不会触发此 bug,只有在下列场景下才会触发:ArrayList
初始化之后(ArrayList 元素非 Object 类型),再次调用 toArray 方法,得到 Object 数组,并且往
Object 数组赋值时,才会触发此 bug。代码和原因如下图:
该bug是由于向上转型造成的,在jdk1.9中被解决 -
集合初始化方式流程
利用该构造函数初始化数组举例
//第一种,利用Array.asList()初始化 ArrayList arrayList1 = new ArrayList<>(Arrays.asList("arrayList","arrayList","arrayList")); System.out.println(arrayList1); //第二种,利用Collection.nCopies()初始化 ArrayList<String> arrayList2 = new ArrayList<>(Collections.nCopies(3, "arrayList")); System.out.println(arrayList2); 输出都是:[arrayList, arrayList, arrayList]
3.2. 无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- tips:无参构造最开始也被初始化为空,只有在首次插入元素扩容时才会将数组大小扩充为10
4. 成员方法
名称 | 修饰符 | 返回值类型 | 参数 | 参数释义 | 返回值 | 返回值释义 | 功能 |
---|---|---|---|---|---|---|---|
trimToSize() | public | void | 无 | 无 | 无 | 无 | 将ArrayList调整为列表当前大小,可以使用该操作最小化ArrayList实例的存储 |
ensureCapacity() | public | void | minCapacity | 期望的最小容量 | 无 | 无 | 预设ArrayList的大小,以提高初始化速度 |
ensureCapacityInternal() | private | void | minCapacity | 期望的最小容量 | 无 | 无 | ArrayList扩容时调用该方法 |
ensureExplicitCapacity() | private | void | minCapacity | 期望的最小容量 | 无 | 无 | 确保ArrayList扩容所需的最小容量能被分配 |
grow() | private | void | minCapacity | 期望的最小容量 | 无 | 无 | 增加容量,以确保它至少可以容纳minimum capacity参数指定的元素数 |
hugeCapacity() | private | static int | minCapacity | 期望的最小容量 | 无 | 无 | 防止ArrayList容量溢出 |
size() | public | int | 无 | 无 | size | ArrayList的长度 | 获取当前ArrayList的长度 |
isEmpty() | public | boolean | 无 | 无 | true/false | 返回ArrayList是否为空 | 判断ArrayList是否为空 |
contains() | public | boolean | Object o | 要测试的是否在ArrayList中存在的元素 | true/false | 元素是否存在 | 判断ArrayList中是否存在某一元素 |
indexOf() | public | int | Object o | 希望在ArrayList中找到的元素 | [-1,Integer.MAX_Value] | 元素是否存在 | 顺序查找并返回某一元素在ArrayList中的位置 |
lastIndexOf() | public | int | Object o | 希望在ArrayList中找到的元素 | [-1,Integer.MAX_Value] | 元素是否存在 | 逆序查找并返回某一元素在ArrayList中的位置 |
clone() | public | Object | 无 | 无 | Object | Object对象数组 | ArrayList浅拷贝 |
toArray() | public | Object[] | 无 | 无 | Object[] | Object对象数组 | 将List转换为数组 |
toArray() | public | T[] | T[] a | 无 | T[] | Object对象数组 | 将List转换为数组(泛型) |
get() | public | E | int index | 索引 | E | index对应的数组元素 | 获取ArrayList指定位置的元素 |
set() | public | E | (int index, E element) | 索引 | E | 更新之前index对应的元素(旧值) | 将ArrayList指定位置的元素替换为指定元素 |
add() | public | boolean | (E e) | 元素 | true/false | 元素是否追加成功 | 在ArrayList末尾追加一个元素 |
add() | public | void | (int index, E element) | (要插入的位置, 要插入的元素) | 无 | 无 | 在指定位置插入一个元素(重载) |
remove() | public | E | int index | 索引 | E | 删除之前index对应的元素(旧值) | 将ArrayList指定位置的元素删除 |
fastRemove() | private | void | int index | 索引 | 无 | 无 | 通过arraycopy方法对ArrayList内的元素进行前移 |
clear() | public | void | 无 | 无 | 无 | 无 | ArrayList长度为0,并清空ArrayList中的所有元素 |
addAll() | public | boolean | (Collection<? extends E> c) | 要添加的集合元素 | true/false | 集合是否添加成功 | ArrayList后追加一个集合 |
addAll() | public | boolean | (int index, Collection<? extends E> c) | 要添加的集合元素及索引 | true/false | 集合是否添加成功 | ArrayList的指定位置追加一个集合(重载) |
removeRange() | protected | void | (int fromIndex, int toIndex) | 要删除元素的索引 | 无 | 无 | 删除ArrayList某一索引区间的元素 |
rangeCheck() | private | void | (int index) | 要检查的索引 | 无 | 无 | 检查某一索引是否超出了ArrayList的大小 |
rangeCheckForAdd() | private | void | (int index) | 要检查的索引 | 无 | 无 | 在调用add()和addAll()时,检查指定索引是否超出了ArrayList的大小 |
outOfBoundsMsg() | private | String | (int index) | 索引 | String | 字符串 | return "Index: “+index+”, Size: "+size; |
removeAll() | public | boolean | (Collection<?> c) | 要删除的集合元素 | true/false | 集合是否删除成功 | 删除arrayList中的元素 |
retainAll() | public | boolean | (Collection<?> c) | 要保留的集合元素 | true/false | 操作是否成功 | 保留只在指定的集合中存在的ArrayList中的元素 |
batchRemove() | private | boolean | (Collection<?> c, boolean complement) | true/false | 操作是否成功 | 批量删除ArrayList中的元素 | |
writeObject() | private | void | (java.io.ObjectOutputStream s) | 无 | 无 | ArrayList自定义的序列化方法 | |
readObject() | private | void | (java.io.ObjectInputStream s) | 无 | 无 | ArrayList自定义的序列化方法 | |
listIterator() | public | ListIterator | (int index) | 指定位置的索引 | ListItr | ListItr对象 | 从ArrayList的指定位置开始,返回一个List迭代器 |
listIterator() | public | ListIterator | 无 | 无 | ListItr | ListItr对象 | 从ArrayList的初始位置开始,返回一个List迭代器 |
Iterator() | public | Iterator | 无 | 无 | Itr | Itr对象 | 从ArrayList的初始位置开始,返回一个迭代器 |
subList() | public | List | (int fromIndex, int toIndex) | 无 | new SubList() | SubList类对象 | 截取ArrayList指定区间的元素,并返回一个SubList内部类 |
subListRangeCheck() | static | void | (int fromIndex, int toIndex, int size) | 索引、ArrayList的大小 | 无 | 无 | SubList前的边界检查 |
spliterator() | public | Spliterator | 无 | 无 | new ArrayListSpliterator<>(this, 0, -1, 0) | 无 | 返回一个ArrayListSpliterator对象 |
forEach() | public | void | (Consumer<? super E> action) | Lamuda表达式 | 无 | 无 | 循环输出ArrayLIstforeach的底层原理是for循环 |
removeIf()见下方代码示例 | public | boolean | (Predicate<? super E> filter) | Lamuda表达式 (函数式接口) | true/false | 操作是否成功 | 删除ArrayList中满足某条件的值 |
replaceAll()见下方代码示例 | public | void | (UnaryOperator operator) | Lamuda表达式 (函数式接口) | true/false | 操作是否成功 | 删除ArrayList中满足某条件的值 |
sort()见下方代码示例 | public | void | (Comparator<? super E> c) | Lamuda表达式 (函数式接口) | true/false | 操作是否成功 | ArrayList排序 |
- Java ArrayList中removeIf()的使用
public class DYHTEST{
static class Person {
private String name;//姓名
private Integer age;//年龄
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public Integer getAge() {
return age;
}
//重写toString,方便观看结果
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
public static void main(String[] args) {
ArrayList<Person> arrayList = new ArrayList(){{
add(new Person("张三", 22));
add(new Person("王五", 34));
add(new Person("赵六", 30));
}};
//过滤30岁以上的人
arrayList.removeIf(person -> person.getAge() >= 30);
System.out.println(arrayList.toString());//查看结果
}
}
-
打印信息
-
Java ArrayList中replaceAll()的使用
ArrayList<Integer> arrayList = new ArrayList(){{ add(22);add(34);add(30);}};
//方式1:三目运算符
arrayList.replaceAll(a -> a.equals(22)?9999999:1);
System.out.println(arrayList.toString());//查看结果
//方式2
arrayList.replaceAll(a -> {
if (a > 25)
a = 88888888;
return a;
});
System.out.println(arrayList.toString());//查看结果
- Java ArrayList中sort()的使用
ArrayList<Integer> arrayList = new ArrayList(){{ add(22);add(34);add(30);}};
//Java8 :lamda表达式
arrayList.sort((ele1,ele2) -> ele1.compareTo(ele2));
//Java8 :引用
arrayList.sort(Integer::compareTo);
System.out.println(arrayList.toString());//查看结果
5. 内部类
5.1 private class Itr implements Iterator
5.1.1 变量
变量名 | 修饰符 | 类型 | 默认值 | 含义 |
---|---|---|---|---|
cursor | ------ | int | ------ | 【游标】要返回的下一个元素的索引 |
lastRet | ------ | int | -1 | 已经返回的最后一个元素的索引 |
expectedModCount | int | ---- | modCount | 预期的ArrayList大小改变的次数 |
5.1.2 方法
名称 | 修饰符 | 返回值类型 | 参数 | 参数释义 | 返回值 | 返回值释义 | 功能 |
---|---|---|---|---|---|---|---|
hasNext() | public | boolean | 无 | 无 | cursor != size | 当前游标指向的是否为最后一个元素 | 判断迭代器是否有下一个元素 |
next() | public | E | 无 | 无 | (E) elementData[i] | 下一个数组元素 | 返回下一个数组元素 |
remove() | public | void | 无 | 无 | 无 | 无 | 删除已返回的最后一个元素 |
forEachRemaining | public | void | (Consumer<? super E> consumer) | Consumer函数式接口,可自定义Lamda表达式 | 无 | 无 | 为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常 |
checkForComodification() | final | void | 无 | 无 | 无 | 无 | 用来实现fail-fast机制 |
fail-fast 机制,即快速失败机制,是java集合(Collection)中的一种错误检测机制。当在迭代集合的过程中该集合在结构上发生改变的时候,就有可能会发生fail-fast,即抛出 ConcurrentModificationException异常。fail-fast机制并不保证在不同步的修改下一定会抛出异常,它只是尽最大努力去抛出,所以这种机制一般仅用于检测bug。
- ArrayList发生fail-fast例子
List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5)); Iterator<Integer> iterator = list.iterator(); int i = 0 ; while(iterator.hasNext()) { if (i == 3) { list.remove(3); } System.out.println(iterator.next()); i ++; }
原因:
5.2 private class ListItr extends Itr implements ListIterator
5.2.1 构造函数
ListItr(int index) {
super();
cursor = index;
}
5.2.2 方法
名称 | 修饰符 | 返回值类型 | 参数 | 参数释义 | 返回值 | 返回值释义 | 功能 |
---|---|---|---|---|---|---|---|
hasPrevious() | public | boolean | 无 | 无 | true/false | true/false | 当前游标(索引)指向的是否是首个元素 |
nextIndex() | public | int | 无 | 无 | cursor | 游标 | 返回下一个元素对应的索引 |
previousIndex() | public | int | 无 | 无 | cursor-1 | 上一个元素对应的索引 | 返回前一个元素对应的索引 |
previous() | public | E | 无 | 无 | (E) elementData[i] | 当前游标对应的上一个元素的值 | 返回当前游标对应的上一个元素的值 |
set() | public | void | (E e) | 无 | 无 | 无 | 设置已经返回的最后一个元素的值 |
add() | public | void | (E e) | 无 | 无 | 无 | 向当前游标位置插入一个值 |
5.3 private class SubList extends AbstractList implements RandomAccess
- RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持《快速随机访问》你可以任意访问该数据结构中的任意一个节点的。也就是说,实现了这个接口的集合是支持 快速随机访问 策略的。如果是实现了这个接口的 List,那么使用for循环的方式获取数据会优于用迭代器获取数据。
- 对ArrayList进行sublist()操作后返回的是SubList类对象,如果直接对该对象进行序列化操作会导致报错,原因是SubList内部类没有实现序列化接口,解决方法为:new ArrayList(SubList)
5.3.1 类变量
变量名 | 修饰符 | 类型 | 默认值 | 含义 |
---|---|---|---|---|
parent | private final | AbstractList | 无 | 父List |
parentOffset | private final | int | 无 | 父List偏移量 |
offset | private final | int | 无 | 偏移量 |
size | private final | int | 无 | SubList类的长度 |
5.3.2 构造函数
SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
5.3.3 方法
名称 | 修饰符 | 返回值类型 | 参数 | 参数释义 | 返回值 | 返回值释义 | 功能 |
---|---|---|---|---|---|---|---|
set() | public | E | (int index, E e) | 索引、元素 | oldValue | 索引对应的旧值 | 设置SubList指定索引位置的值 |
get() | public | E | (int index) | 索引 | ArrayList.this.elementData | 索引对应的值 | 获取SubList指定索引位置的值 |
size() | public | int | 无 | 无 | this.size | SubList的长度 | 获取SubList的长度 |
add() | public | void | (int index, E e) | 索引、元素 | 无 | 无 | 向SubList中添加元素 |
remove() | public | E | (int index) | 索引 | result | 删除元素的值 | 移除SubList末尾位置的值 |
removeRange() | protected | void | (int fromIndex, int toIndex) | 区间 | 无 | 无 | 删除指定索引区间的值 |
addAll() | public | boolean | (Collection<? extends E> c) | 要添加的集合元素 | true/false | 集合是否添加成功 | ArrayList后追加一个集合 |
addAll() | public | boolean | (int index, Collection<? extends E> c) | 要添加的集合元素及索引 | true/false | 集合是否添加成功 | ArrayList的指定位置追加一个集合(重载) |
listIterator() | public | ListIterator | (final int index) | 指定位置的索引 | ListItr | ListItr对象 | 从ArrayList的指定位置开始,返回一个List迭代器 |
Iterator() | public | Iterator | 无 | 无 | Itr | Itr对象 | 从ArrayList的初始位置开始,返回一个迭代器 |
subList() | public | List | (int fromIndex, int toIndex) | 无 | new SubList() | SubList类对象 | 截取ArrayList指定区间的元素,并返回一个SubList内部类 |
rangeCheck() | private | void | (int index) | 要检查的索引 | 无 | 无 | 检查某一索引是否超出了ArrayList的大小 |
rangeCheckForAdd() | private | void | (int index) | 要检查的索引 | 无 | 无 | 在调用add()和addAll()时,检查指定索引是否超出了ArrayList的大小 |
outOfBoundsMsg() | private | String | (int index) | 索引 | String | 字符串 | return "Index: “+index+”, Size: "+size; |
checkForComodification() | final | void | 无 | 无 | 无 | 无 | 用来实现fail-fast机制 |
5.4 static final class ArrayListSpliterator implements Spliterator
Spliteratorjdk8新增用于遍历和分隔一个对象中的元素,这个对象必须实现Spliterator接口,实现这个接口类有Collection,数组等。
Spliterator可以逐个的遍历元素,或者批量的遍历。
Spliterator是一个可以分割的迭代器,可以将Spilterator实例分割成多个小的Spilterator实例。
5.4.1 类变量
变量名 | 修饰符 | 类型 | 默认值 | 含义 |
---|---|---|---|---|
list | private final | ArrayList | 无 | ArrayList |
index | private | int | 无 | 【游标】当前索引,在前进/拆分时修改 |
fence | private | int | 无 | 默认-1,直到被使用变为最后一个元素的索引【边界值】 |
expectedModCount | private | int | 无 | 预期的ArrayList改变的次数 |
5.4.2 构造函数
/** Create new spliterator covering the given range */
ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) {
this.list = list; // OK if null unless traversed
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
}
5.4.3 方法
名称 | 修饰符 | 返回值类型 | 参数 | 参数释义 | 返回值 | 返回值释义 | 功能 |
---|---|---|---|---|---|---|---|
getFence() | private | int | 无 | 无 | 最后一个元素的位置 | 最后一个元素的位置 | 初始化fence(最后一个元素的位置) |
trySplit() | public | ArrayListSpliterator | 无 | 无 | new ArrayListSpliterator() | 返回一个新分割出的spilterator实例 | 分割list,返回一个新分割出的spilterator实例类似二分法分割,可递归哦 |
tryAdvance() | public | boolean | (Consumer<? super E> action) | 可以是正则表达式 | boolean | boolean | 返回true时,表示可能还有元素未处理 返回falsa时,没有剩余元素处理了 |
forEachRemaining | public | void | (Consumer<? super E> consumer) | Consumer函数式接口,可自定义Lamda表达式 | 无 | 无 | 为每个剩余元素执行给定的操作,直到所有的元素都已经被处理或行动将抛出一个异常 |
estimateSize | public | long | 无 | 无 | return (long) (getFence() - index) | 无 | 估算剩余长度 |
characteristics | public | int | 无 | 无 | return (long) (getFence() - index) | 无 | 返回特征值 |
5.4.4 spliterator代码示例
ArrayList<Integer> arrayList = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
Spliterator spliterator = arrayList.spliterator();
//估算剩余长度
System.out.println(spliterator.estimateSize());
//输出剩余的元素
spliterator.forEachRemaining(System.out::print);
System.out.println();
ArrayList<Integer> arrayList1 = new ArrayList(Arrays.asList(1,2,3,4,5,6,7,8,9,10));
Spliterator spliterator1 = arrayList.spliterator();
//估算剩余长度
System.out.println(spliterator1.estimateSize());
//输出特征值
System.out.println(spliterator1.characteristics());
//输出分割后的值
spliterator1.trySplit().forEachRemaining(System.out::print);
6. ArrayList的扩容机制
- ArrayList容量不够时,会采用位运算将容量扩充为原来的【1.5】倍。
- 无参构造在构造时会初始化为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA -> {} ,并在首次插入元素时,初始化数组容量为 【10】,注意数组容量为10并不意味着size为10。
- 有参构造传入值为0或集合长度为0时,会初始化为 EMPTY_ELEMENTDATA -> {} ,并在首次插入元素时,初始化数组容量为 【1】,即按照传入的参数来确定创建数组的大小
6.1 自动扩容链路
ArrayList的自动扩容机制底层借助于native方法实现System.arraycopy,如果频繁的对ArrayList进行扩容,则会进行大量IO操作,导致性能降低。因此通过有参的构造函数预设可存储元素的个数,能够避免ArrayList自动扩容,提高其性能。