源码分析:Java 集合类之 ArrayList

本文详细探讨了ArrayList的源码,重点分析了其扩容机制,包括grow()方法、System.arraycopy()、Arrays.copyOf()在扩容过程中的作用。还提到了ArrayList的ensureCapacity()方法用于预先指定容量以减少扩容次数,并简要介绍了删除元素的操作。
摘要由CSDN通过智能技术生成

ArrayList 源码+扩容机制

  • ArrayList 的底层数据结构是数组,它的容量可以动态增加。在添加大量元素前可以通过 ensureCapacity() 来指定增加的容量,可以减少递增式再分配的数量。
  • ArrayList 实现的 RandomAccess 接口是一个标志接口,表明这个 List 集合是支持快速随机访问的。比如在 Collections.binarySearch() 中,调用的是 Collections.indexedBinarySearch() 方法,而不是 Collections.iteratorBinarySearch() 方法。
  • new ArrayList<>(0)new ArrayList<>() 返回的是静态变量空数组,但不是同一个。通过默认构造方法得到的 ArrayList 等到执行 add() 添加元素时才会初始化容量(默认为 10),而指定初始化容量为 0 的 ArrayList 在 ensureCapacity()
扩容机制
  • add(int index, E element)

    • **rangeCheckForAdd(index);**如果 index 大于 size,或小于 0,抛出异常 IndexOutOfBoundsException
    • ensureCapacityInternal(size + 1);
      • **ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
        • **grow(int minCapacity);**扩容的核心方法
    • System.arraycopy(…);复制到新的更大的数组,native 方法
  • addAll(Collection<? extends E> c)

    • ensureCapacityInternal(size + 1);

      • *ensureExplicitCapacity();**判断是否需要扩容(Explicit 明确的)
        • **grow(int minCapacity);**扩容的核心方法
    • System.arraycopy(…);复制到新的更大的数组,native 方法

private void grow(int minCapacity)
  1. 选取新的容量值 newCapacity :minCapacity 和 原数组长度的 1.5 倍 中的较大值。
  2. 检查 newCapacity 是否超出 MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8):超出则取 Integer.MAX_VALUE。
  3. 通过 Arrays.copyOf() 得到新的数组。
System.arrayCopy()

public static void arraycopy(Object src, int srcPos,

​ Object dest, int destPos,

​ int length)

源阵列中位置 [srcPos, srcPos+length-1] 的组件分别复制到目标阵列的位置 [destPos , destPos+length-1] 。

Arrays.copyOf()

public static T[] copyOf(T[] original, int newLength)

  1. 申请一个大小为 newLength 的新数组
  2. 通过 System.arraycopy 将原数组的数据拷贝到新数组
  3. 返回新数组
暴露的 ensureCapaticy 方法
// @param minCapacity 所需的最小容量
public void ensureCapaticy(int minCapacity) {
   
    // 判断初始化容量是否为 0
    ...
    ensureExlicitCapacity(minCapacity);
}

在 add 大量元素之前,使用该方法指定容量,以减少增量重新分配的次数。

删除元素操作

删除指定位置的元素,将所有后续元素移到左侧。可能会改变数组中其他元素的位置,但不会改变 容量。

  • remove()
  • fastRemove()
  • removeRange()
附源码 (摘抄自 JavaGuide)

https://javaguide.cn/java/collection/arraylist-source-code/

package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;


public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
   
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空数组(用于空实例)。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {
   };

     //用于默认大小空实例的共享空数组实例。
      //我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
   };

    /**
     * 保存ArrayList数据的数组
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList 所包含的元素个数
     */
    private int size;

    /**
     * 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
     */
    public ArrayList(int initialCapacity) {
   
        if (initialCapacity > 0) {
   
            //如果传入的参数大于0,创建initialCapacity大小的数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
   
            //如果传入的参数等于0,创建空数组
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
   
            //其他情况,抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     *默认无参构造函数
     *DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
     */
    public ArrayList() {
   
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
     */
    public ArrayList(Collection<? extends E> c) {
   
        //将指定集合转换为数组
        elementData = c.toArray();
        //如果elementData数组的长度不为0
        if ((size = elementData.length) != 0) {
   
            // 如果elementData不是Object类型数据(c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断)
            if (elementData.getClass() != Object[].class)
                //将原来不是Object类型的elementData数组的内容,赋值给新的Object类型的elementData数组
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
   
            // 其他情况,用空数组代替
            this.elementData = EMPTY_ELEMENTDATA;
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quantum_Wu

一起加油呀ヾ(◍°∇°◍)ノ゙

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值