从名字就可以看得出来,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 方法执行完毕。