【源码解析】- ArrayList源码解析,绝对详细

本文详细解析了ArrayList的源码,包括其基于数组的数据结构、优缺点、成员变量、构造函数和主要操作函数。重点讨论了添加、移除、修改和查询元素的实现,尤其是System.arraycopy在扩容和移动元素中的应用。
摘要由CSDN通过智能技术生成

ArrayList源码解析

简介

ArrayListJava集合框架中非常常用的一种数据结构。继承自AbstractList,实现了List接口。底层基于数组来实现动态容量大小的控制,允许null值的存在。同时还实现了RandomAccessCloneableSerializable接口,支持快速访问、复制、序列化操作。

了解数组

数组简单来说就是将所有的数据排成一排存放在系统分配的一个内存块上,通过使用特定元素的索引作为数组的下标,可以在常数时间内访问数组元素的这么一个结构;

数组优缺点

优点

  • 简单方便已使用
  • 访问元素快

缺点

  • 大小固定:数组的大小是静态的,在使用前必须确定好数组的大小
  • 分配一个连续空间块:数组初始分配空间时,有时候无法分配能存储整个数组的内存空间(当数组规模太大时);
  • **基于位置的插入操作实现复杂:**如果要在数组中的给定位置插入元素,那么可能就会需要移动存储在数组中的其他元素,这样才能腾出指定的位置来放插入的新元素;而如果在数组的开始位置插入元素,那么这样的移动操作开销就会很大。

ArrayList解析

我们提到数组的特点是大小固定,ArrayList的底层是基于数组来实现容量的大小动态变化的,那我们一起来结合源码看看,是如何实现这一功能的。

我们找到java.util.ArrayList包查看代码。并通过注释的方式,一起来揭开面纱。

1、成员变量

// 默认的容量大小
private static final int DEFAULT_CAPACITY = 10;
// 空数组对象Object
private static final Object[] EMPTY_ELEMENTDATA = {
   };
// 有一个空数据对象Object
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
   };
// 默认修饰且不参与序列化的 数组对象,也是实际存储数据的地方
transient Object[] elementData; // non-private to simplify nested class access
// 实际大小容量
private int size;

我们发现有两个一样的空数组对象,为什么要用两个呢?源代码中也进行来解释 We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added.

也就是说,这是一个共享的空数组实例,通过与默认的空数组区分开,好处是,添加元素时知道该 elementData 从空的构造函数还是有参构造函数被初始化的。以便确认如何扩容。

AbstractList父类中还有一个变量

protected transient int modCount = 0;

用来记录对List的操作次数。作用在使用Iterator时,防止在迭代过程中集合被修改。

2、构造函数

无参数构造

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
   
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

默认的无参数构造中直接给elementData赋值来一个空的数据。但我们看到注释上说初始容量为10的数组,这好像不太对啊。其实这只是一个延后的操作,当第一次添加数据进去时,容量会扩容到10,好处是避免无用的ArrayList的出现。具体的实现我们接着往后看。

指定初始容量构造

public ArrayList(int initialCapacity) {
   
    // 指定的容量大于0,直接new一个指定容量大小的数组
    if (initialCapacity > 0) {
   
    this.elementData = new Object[initialCapacity];
    // 指定容量等于0。那就赋值空数组。
    } else if (initialCapacity == 0) {
   
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
   
	// 无效容量大小
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

这个还是比较清晰的,根据指定容量初始化一个数组。加入了容量大小的判断操作。

指定Collection集合构造

public ArrayList(Collection<? extends E> c) {
   
    // 首先转成数组
    Object[] a = c.toArray();
    // 有效大小的数组哈
    if ((size = a.length) != 0) {
   
      // 这里做了优化,如果也是一个ArrayList集合直接赋值即可
      if (c.getClass() == ArrayList.class) {
   
            elementData = a;
        } else {
   
	    // 其他的类型就做拷贝啦
            elementData = Arrays
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值