注:本文解析的 ArrayList 源代码基于 Java 1.8 。
Header
之前讲了 HashMap 的原理后,今天来看一下 ArrayList 。
ArrayList 也是非常常用的集合类。它是有序的并且可以存储重复元素的。 ArrayList 底层其实就是一个数组,并且会动态扩容的。
源码分析
构造方法
1 | public ArrayList(int initialCapacity) { |
构造方法中的代码比较简短,大家都能理解的吧。
add()
1 | public boolean add(E e) { |
发现在 add()
方法中,代码很简短。可以看出之前的预操作都放入了 ensureCapacityInternal
方法中,这个方法会去确保该元素在数组中有位置可以放入。
那么我们来看看这个方法:
1 | private void ensureCapacityInternal(int minCapacity) { |
看了半天,扩容是在 grow 方法中完成的,所以我们接着跟进。
1 | private void grow(int minCapacity) { |
扩容方法其实就是新创建一个数组,然后将旧数组的元素都复制到新数组里面。
当然,add 还有一个重载的方法 add(int index, E element)
,顺便我们也来看一下。
1 | public void add(int index, E element) { |
好了,add 方法看的差不多了,剩下还有一个 addAll(Collection<? extends E> c)
方法也是换汤不换药的,可以自己回去看下,这里就不讲了。
get()
get 方法很简单,就是在数组中返回指定位置的元素即可。
1 | public E get(int index) { |
remove()
1 | public E remove(int index) { |
remove 中主要是将之后的元素都向前一位移动,然后将最后一位的值设置为空。最后,返回已经删除的值。
同样,remove 还有一个重载的方法 remove(Object o)
。
1 | public boolean remove(Object o) { |
clear()
clear 方法无非就是遍历数组,然后把所有的值都置为 null 。
1 | public void clear() { |
Footer
至此,ArrayList 主要的几个方法就讲完了。ArrayList 的源码还是比较简单的,基本上都可以看得明白。
我们来总结一下:
- ArrayList底层是基于数组来实现的,因此在 get 的时候效率高,而 add 或者 remove 的时候,效率低;
- 调用默认的 ArrayList 无参构造方法的话,数组的初始容量为 10 ;
- ArrayList 会自动扩容,扩容的时候,会将容量扩至原来的 1.5 倍;
- ArrayList 不是线程安全的;
那么今天就这样了,之后有空给大家讲讲 LinkedList 。