ArrayList源码解析
ArrayList的结构
ArryList是一个泛型类它继承了 AbstractList<E>,实现了RandomAccess、List、Cloneable, java.io.Serializable接口
因此它具有列表的添加、删除、查找、并且可以快速访问(通过下标)等功能。
在ArrayList的源码中我们可以看到
说明ArrayList底层是基于Object数组实现的。
而为了满足数组长度的动态变化,ArrayList还有很多关于ArrayList容量的函数
而常规的集合添加,删除,查询相关的函数这就不探讨了。比较简单
ArrayList扩容流程
下面我们以一个空ArrayList添加一个元素演示这个扩容流程
-
用无参构造方法创建出一个ArrayList
ArrayList<Integer> list =new ArrayList<>();
此时执行这样的代码:
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
将elementData数组 初始化为空数组 此时size = 0 数组元素数为0
-
执行add方法添加一个元素
list.add(1)
此时执行这样的代码
public boolean add(E a) { ensureCapacityInternal(size + 1);//此时size + 1 = 1因为这里是第一次添加元素 elementDate[size ++] = e; return true; }
-
进入ensureCapacityInternal方法中
//只是调用2个方法 private void ensureCapacityInternal(int minCapacity) { // minCapacity = 1 ensureExplicitCapacity(calculateCapacity(elementData,minCapacity)) } private static int calculateCapacity(Object[] elementData, int minCapacity) { // minCapacity = 1 //当前集合是不是空数组 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //是,由于DEFAULT_CAPACITY = 10,minCapacity = 1 //返回10 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } //再进入方法ensureExplicitCapacity private void ensureExplicitCapacity(int minCapacity) { //modCount做修改判断的 modCount++; // overflow-conscious code //此时元素还未加入到elementData中 所以数组长度为0 进行扩容 if (minCapacity - elementData.length > 0) //扩容的核心方法 grow(minCapacity); }
-
核心扩容方法grow(int minCapacity)
private void grow(int minCapacity) { int oldCapacity = elementData.length; //oldCapacity = 0 int newCapacity = oldCapacity + (oldCapacity >> 1)// 扩容为old的1.5倍 if(newCapacity - minCapacity < 0) { //不足 newCapacity = minCapacity; } //是否超过规定长度 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //利用Arrays.copy对数组赋值。也就是说 数组的长度为newCapacity elementData = Arrays.copyOf(elementData, newCapacity); }
ArrayList的内部类
在看源码的途中的我还发现了
Itr、ListItr、SubList、ArrayListSplierator这几个内部类
Itr
Itr实现了迭代器接口,目的是为ArrayList提供迭代器的遍历方式,这就让我们可以使用foreach的形式来遍历
ArrayList<Integer> list = new ArrayList<>();
Iterator<Integer> = list.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
ListItr
ListItr也是为ArrayList提供了遍历方式,比如双向遍历和允许修改元素和添加元素(expectedModCount = modCount)
ListIterator<String> listItr = list.listIterator();
while (listItr.hasNext()) {
System.out.println(listItr.next());
}
while (listItr.hasPrevious()) {
System.out.println(listItr.previous());
}
SubList
SubList是ArrayList的子列表实现,调用subList(int fromIndex, int toIndex)会返回一个SubList实例,这个子列表视图可以对原列表的部分进行操作,而不会创建 新的列表
//[A,B,C,D]
List<String> subList = list.subList(1, 3);
System.out.println(subList); // 输出: [B, C]
subList.set(0, "E");
System.out.println(list); // 输出: [A, E, C, D]
ArrayListSplierator
基本介绍
Splierator是Java8引入的一种新的迭代器,用于并行遍历和分割集合中的元素,ArrayListSplierator是它的实现类
trySplit()
: 将当前 Spliterator
拆分成两个 Spliterator
,返回一个新的 Spliterator
处理一部分元素,保留原来的 Spliterator
处理剩下的部分。这个方法在并行流处理中非常重要,可以实现数据的分治处理。
tryAdvance(Consumer<? super T> action)
: 如果还有剩余元素,处理当前元素并返回 true
,否则返回 false
。这个方法用于顺序处理元素。
forEachRemaining(Consumer<? super T> action)
: 对剩余的每个元素执行给定的操作,直到处理完所有元素或出现错误。这个方法用于处理剩余的所有元素。
estimateSize()
: 返回 Spliterator
中剩余元素的估计大小。
characteristics()
: 返回 Spliterator
的特性,比如 ORDERED
、DISTINCT
、SORTED
、SIZED
、NONNULL
、IMMUTABLE
、CONCURRENT
、SUBSIZED
等。
挖掘
下面我们来使用下spliterator
ArrayList<Integer> objects = new ArrayList<>();
objects.spliterator().forEachRemaining(System.out::println);
我发现这和stream流的形式不是很像吗?
objects.stream().forEach(System.out::println);
然后我就点进这个stream中发现
然后经过调试发现
所以我们可以认为ArrayList中的这个spliterator就是为stream提供支撑的。
并且stream().parallel()串行流,它不也是和这个Splierator用于并行遍历和分割集合中的元素的理念相符合
当然如果看过stream流的源码应该是知道,不过我没看过,所以就觉得很有意思,感觉东西都串起来了