ArrayList你不知道的扩容机制,快学起来

相信大家学Java基础的时候,多多少少肯定听过一些关于ArrayList的扩容机制分析。基本上都是这么讲的:

  1. 当new ArrayList<>()后,底层会创建一个长度为0的数组
  2. 当调用add方法添加一个元素时,ArrayList底层会创建一个长度为10的数组,然后将新增元素添加到数组末尾
  3. 当添加元素后,元素个数超过10之后,就会触发ArrayList的自动扩容机制,默认扩容为原数组的1.5倍

这里这么讲其实是不严谨的,因为ArrayList中还有一个成员方法叫addAll,传递的参数为一个Collection集合,当达到10个上限后,我一次性添加100个元素,这个时候扩容1.5倍是不够,这个时候就需要按需扩容,我们来看下ArrayList的底层源码:

1. ① new ArrayList<>() ② new ArrayList<>(int size) ③ new ArrayList<>(Collection<? extends E> c)
1.1 new ArrayList<>() 空参构造

当我们new一个ArrayList的时候,如果我们不进行参数传递,其实这个时候ArrayList底层默认创建一个Object类型的数组:
空参构造

其中的常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA就是默认的Object[]
DEFAULTCAPACITY_EMPTY_ELEMENTDATA

1.2 new ArrayList<>(int size) 带数组长度的构造

如果new ArrayList的时候传递了初始数组大小,那么ArrayList底层将会帮你创建一个你传递长度的数组,但是这个时候也需要进行长度参数判断:

  • 大于0,则按照你传递的参数进行创建
  • 等于0,按照空参构造的方式进行创建空数组
  • 小于0,报错
    带数组长度的构造
1.3 new ArrayList(Collection<? extends E> c) 带集合参数的构造
  • 首先将传入的集合转换为数组,然后判断数组的长度是否等于0
    • 等于0,则还是按照空参构造的方式进行创建数组
    • 不等于0,则判断当前传入的集合是否是ArrayList集合,
      • 如果是,则直接将转换后的a数组赋值给当前ArrayList的数组
      • 如果不是,则使用Arrays中的copyOf方法将该数组进行二次复制,
  • 这里就会有人问了,前面我已经进行toArray转换了,为什么这里还需要分情况判是否是ArrayList集合,再去判断时候需要二次复制?作者也有这样的疑惑,网上查阅了相关资料后,分享给大家:如果 c 是 ArrayList 类型,那么它的底层实现也是一个数组,因此可以直接使用 elementData = a; 进行赋值。这样做可以避免额外的数组复制操作,提高效率。如果 c 不是 ArrayList 类型,那么使用 Arrays.copyOf(a, size, Object[].class); 创建一个新的数组。
    这里使用 Arrays.copyOf 的原因在于安全性和隔离性。如果不使用 copyOf,而是直接将原数组赋值给 elementData,那么原数组和 ArrayList 的 elementData 就会共享同一块内存区域。这意味着,如果在其他地方修改了原数组的内容,那么 ArrayList 中的数据也会被修改,这可能会导致一些不可预见的错误。通过使用 Arrays.copyOf,我们可以创建一个新的数组,这样 ArrayList 的 elementData 就和原数组是完全独立的,更加安全。
    这种做法也符合Java中的封装原则,即每个对象都应该对自己的内部状态负责,不应该被外部对象直接修改。

带集合参数的构造

2. add(E e) 添加元素

添加元素
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

其中最主要的扩容代码为红色框中的代码,表示判断当前最小扩容大小和默认扩容大小进行对比,哪个大,使用哪个,这里就解释了为什么1.5倍扩容机制是不严谨的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Kkuil

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值