前言
对于Java程序员,可以说对于 ArrayList
和 LinkedList
可谓是十分熟悉了
对于ArrayList和LinkedList,他们都是List接口的一个实现类,并且我们知道他们的实现方式各不相同,例如ArrayList底层实现是一个数组,而LinkedList底层实现是链表,对于数组来说,插入慢但是查询快,而对于链表来说查询慢,插入快
今天我们就来分析分析他们的源码
ArrayList
我们先看一看ArrayList的类图。他继承于AbstractList,而这个类是List类的的骨架,可以说这个类是List类的基石
成员属性
/**
序列化ID
**/
private static final long serialVersionUID = 8683452581122892189L;
/**
默认容量
**/
private static final int DEFAULT_CAPACITY = 10;
/**
如果传入的容量为0,那么将使用这个空元素数组
**/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
默认空元素数组,长度为0,传入元素时会初始化为默认元素大小
**/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
真正存储数据的数组
**/
transient Object[] elementData;
/**
列表中元素的个数
**/
private int size;
这里需要主要关注的成员属性为 size
和 elementData
,一个是元素个数,一个是真正存储数据的数组
构造函数
/**
指定数组长度构造
**/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
空参构造
**/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
传入一个集合,将该集合的元素初始化到ArrayList种
**/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
扩容机制
我们知道ArrayList是一个动态数组,但是他的底层实现是一个数组,那他是怎样保证动态的呢?
ArrayList每次添加元素之前,都会检查添加元素后的元素个数是否超过数组长度,如果超出,那么就会进行扩容,而数组扩容通过一个公开的方法实现,我们也可以手动进行扩容
public void ensureCapacity(int minCapacity) {
//判断数组是否等于默认空数组,不等于则给minExpand赋值为10
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0 : DEFAULT_C