arrayList集合源码分析
分析arraylistj就离不开数组,数组是数结构中很基本的结构,很多的编程语言都内置数据。在java中,当创建数组时会在内存中划分出一块连续的内存,然后当有数据进入的时候会将数据按顺序的存储在这一块连续的内存中,当需要读取数组中的数据的时候,需要提供数组中的索引,然后数组根据索引将内存中的数据取出来,返回给读取程序。在java中并不是所有的数据都能存储到数组中,只有相同类型的数据才可以一起存储到数组中。
1 | 2 | 3 | 4 | 5 | 6 | 7 | ... | n-1 | n |
因为数组在存储数据时是按顺序存储的,存储数据的内存也是连续的,所以他的特点就是寻址读取数据比较容易,插入和删除比较困难。
我们可以进入到jdk的源码里面去看一下,idea默认就支持源码的阅读,但是不可以修改哈。
首先我们可以看到ArrayList是继承了AbstractList并且实现了 List<E>, RandomAccess, Cloneable, java.io.Serializable这几个接口的。那实现这几个接口有什么用呢?
1,RandomAccess接口是一个标记接口,用以标记实现的List集合具备快速随机访问的能力。
那么什么是随机访问的能力呢?其实很简单,随机访问就是随机的访问List中的任何一个元素。
所有的List实现都支持随机访问的,只是基于基本结构的不同,实现的速度不同罢了,这里的快速随机访问,那么就不是所有List集合都支持了。
二者的差距显而易见,所以ArrayList具备快速随机访问功能,而LinkedList没有。
实现了RandomAccess这个接口有什么用呢?当一个List拥有快速访问功能时,其遍历方法采用for循环最快速。而没有快速访问功能的List,遍历的时候采用Iterator迭代器最快速。
2,Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆,能使用Object.clone()方法。如果没有实现 Cloneable的类对象调用clone()就会抛出CloneNotSupportedException。关于对象的克隆请参考对象克隆。 ArrayList里面实现的是深拷贝。
public Object clone() { try { ArrayList<?> v = (ArrayList<?>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } }
3,Serializable是标记型的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。
下面看一下ArrayList里面的属性:
// 初始容量 private static final int DEFAULT_CAPACITY = 10; // 实例化空数组的时候,使用的共享数组 private static final Object[] EMPTY_ELEMENTDATA = {}; // 共享的空数组实例,用于默认大小的空实例。 我们将此与EMPTY_ELEMENTDATA区别开来, //以了解添加第一个元素时需要充气多少。 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存储ArrayList的元素的数组缓冲区。 * ArrayList的容量是此数组缓冲区的长度。 添加第一个元素时,任何具有elementData == * DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都将扩展为DEFAULT_CAPACITY。 */ transient Object[] elementData; // non-private to simplify nested class access // List的容量 private int size;
通过这个Object[] elementData我们可以看到,arraylist的底层是一个数组。