聊聊Java ArrayList,扩容机制了解吗?

 从名字就可以看得出来,ArrayList 实现了 List 接口,并且是基于数组实现的。

数组的大小是固定的,一旦创建的时候指定了大小,就不能再调整了。也就是说,如果数组满了,就不能再添加任何元素了。ArrayList 在数组的基础上实现了自动扩容,并且提供了比数组更丰富的预定义方法(各种增删改查),非常灵活。

Java 这门编程语言和别的编程语言,比如说 C语言的不同之处就在这里,如果是 C语言的话,你就必须得动手实现自己的 ArrayList,原生的库函数里面是没有的。

01、创建 ArrayList

可以通过上面的语句来创建一个字符串类型的 ArrayList(通过尖括号来限定 ArrayList 中元素的类型,如果尝试添加其他类型的元素,将会产生编译错误),更简化的写法如下:

由于 ArrayList 实现了 List 接口,所以 alist 变量的类型可以是 List 类型;new 关键字声明后的尖括号中可以不再指定元素的类型,因为编译器可以通过前面尖括号中的类型进行智能推断。

此时会调用无参构造方法(见下面的代码)创建一个空的数组,常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA的值为 {}

如果非常确定 ArrayList 中元素的个数,在创建的时候还可以指定初始大小。

这样做的好处是,可以有效地避免在添加新的元素时进行不必要的扩容。

02、向 ArrayList 中添加元素

可以通过 add() 方法向 ArrayList 中添加一个元素。

alist.add("韩子谦");

我们来跟一下源码,看看 add 方法到底执行了哪些操作。跟的过程中,我们也可以偷师到 Java 源码的作者(大师级程序员)是如何优雅地写代码的。

来具体看一下,先是 add() 方法的源码(已添加好详细地注释)

参数 e 为要添加的元素,此时的值为“韩子谦”,size 为 ArrayList 的长度,此时为 0。

继续跟下去,来看看 ensureCapacityInternal()方法:

此时:

  • 参数 minCapacity 为 1(size+1 传过来的)
  • elementData 为存放 ArrayList 元素的底层数组,前面声明 ArrayList 的时候讲过了,此时为空 {}
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA 前面也讲过了,为 {}

所以,if 条件此时为 true,if 语句minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity)要执行。

DEFAULT_CAPACITY 为 10(见下面的代码),所以执行完这行代码后,minCapacity 为 10,Math.max() 方法的作用是取两个当中最大的那个。

接下来执行 ensureExplicitCapacity() 方法,来看一下源码:

此时:

  • 参数 minCapacity 为 10
  • elementData.length 为 0(数组为空)

所以 10-0>0,if 条件为 true,进入 if 语句执行 grow() 方法,来看源码:

此时:

  • 参数 minCapacity 为 10
  • 变量 oldCapacity 为 0

所以 newCapacity 也为 0,于是 newCapacity - minCapacity 等于 -10 小于 0,于是第一个 if 条件为 true,执行第一个 if 语句 newCapacity = minCapacity,然后 newCapacity 为 10。

紧接着执行 elementData = Arrays.copyOf(elementData, newCapacity);,也就是进行数组的第一次扩容,长度为 10。

回到 add() 方法:

执行 elementData[size++] = e

此时:

  • size 为 0
  • e 为 “韩子谦”

所以数组的第一个元素(下标为 0) 被赋值为“沉默王二”,接着返回 true,第一次 add 方法执行完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值