ArrayList源码解析

本文详细介绍了ArrayList的内部工作机制,包括默认容量、空参与有参构造器的区别、add方法的执行流程、扩容机制以及get和remove方法的实现。重点关注ArrayList的扩容策略,每次扩容为原长度的1.5倍,并通过举例说明了扩容过程。此外,对比了ArrayList与Vector在线程安全和扩容策略上的差异。
摘要由CSDN通过智能技术生成

ArrayList源码解析

了解ArrayList

在项目中大家肯定经常使用ArrayList,但是你对ArrayList了解多少呢?

  • ArrayList实现了List接口
  • 底层存储数据使用数组存储
  • 内存满时会自动触发扩容机制

ArrayList有很多值得学习的地方,接下来我们更深入的了解ArrayList。

ArrayList中的参数

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

创建ArrayList

创建ArrayList的方法非常简单,相信大家都使用过,通常会使用以下两种情况来创建

//调用空参构造器
ArrayList<String> list1 = new ArrayList<>();
//调用有参构造器
ArrayList<String> list2 = new ArrayList<>(10);

空参构造器

DEFAULTCAPACITY_EMPTY_ELEMENTDATA是空数组,使用空参构造器创建的ArrayList是一种懒加载的模式

也就是说创建ArrayList时并不设定他的大小,而是在使用的时候设置数组大小

public ArrayList() {
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

有参构造器

而在有参构造器的情况下

如果参数大于0,则是直接将数组的长度定下来

如果等于0,也是一个空数组,相当于空参构造器

如果小于0,则会抛出异常

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);
    }
}

ArrayList中的add方法

初始化ArrayList时,size的默认值为0,所以先执行的是ensureCapacityInternal(1);

在这里插入图片描述

在这里插入图片描述

也就是说我们最先执行的方法是calculateCapacity(elementData, 1)

如果当前数组是空的话,他会将传入的1与DEFAULT_CAPACITY(10)做比较,返回较大的那个,在这个情况下我们会返回10,然后执行ensureExplicitCapacity(10);

在这里插入图片描述

modCount是用来记录该集合被修改的次数,这个暂时不需要深入研究

接下来执行判断语句,minCapacity是10,而当前数组是空的,所以必定会触发grow(10)

在这里插入图片描述

grow也是我们的扩容方法,这里其实算是触发了扩容,当前的数组长度为0,存入一个数据触发扩容,这套逻辑走下来,newCapaciry为10,也就是会触发elementData = Arrays.copyOf(elementData, 10);

这里介绍一下Arrays.copyOf(array,size):返回一个新的数组对象,size指的是新数组对象的长度,如果超过了原数组长度,则保留数组默认值,并且将array复制到新的数组

到此我们知道了,调用空参构造器创建的ArrayList是以懒加载的方式执行,并且在第一次add时默认大小为10

在这里插入图片描述

ArrayList的扩容

其实在第一次add的方法执行时,就已经进行过一遍ArrayList的扩容,我们不妨在进一步的了解一下它的扩容机制

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
        list.add("a");
    }

ArrayList的默认大小为10,当我们执行第11次add方法时,会自动触发扩容

按照上述add方法执行下来,最终会走到grow方法中,并且参数是11

这里我们注意第二行代码int newCapacity = oldCapacity + (oldCapacity >> 1);,这行代码非常清晰的想我们展示了ArrayList的扩容因子是1.5,也就是说每次扩容都是原数组长度的1.5倍

在这里插入图片描述

ArrayList的get方法

get方法的源码非常的简单,一步校验,一步返回

在这里插入图片描述

rangeCheck方法作用是判断下标是否越界

在这里插入图片描述

直接返回指定下标的数组的元素

在这里插入图片描述

ArrayList的remove方法

对于remove(int)方法,ArrayList会先删除数组中该下标的元素,并且让它后面所有的元素都前一一位,将最后一个下标的位置置为null。

介绍一个方法:System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

  • src:原数组
  • srcPos:原数组要复制的起始位置
  • dest:目标数组
  • destPos:目标数组放置的起始位置
  • length:复制的长度

在这里插入图片描述

Vector与ArrayList的区别

相同点

  • 初始容量都是10
  • 底层都是基于数组实现

不同点

  • ArrayList线程不安全,Vector线程安全

  • 虽然初始容量都是10,但ArrayList是懒加载,而Vector是直接创建空间

  • 默认情况下,ArrayList的扩容因子是1.5,Vector的扩容因子是2

  • Vector可以手动设置扩容因子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值