目录
一、概念
二、源码分析
1、属性
2、构造器
①空构造
②指定初始容量(initialCapacity)构造器
②参数为Collection的构造器
3、常用方法
①public boolean add(E e)
②public void add(int index, E element)
③其他方法
三、总结
一、概念
java.util.ArrayList 是Java中的常用类,它实现了List接口,能够存储任意类型的数据。ArrayList底层是通过数组实现的,因此它具有快速随机访问的特性。
二、源码分析
1、属性
DEFAULT_CAPACITY(默认容量)是一个常量10
EMPTY_ELEMENTDATA 与 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 都是常量空集合
elementData 是ArrayList内部维护的数组
size为ArrayList的长度
2、构造器
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_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(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;
}
}
①空构造
将维护的数组(elementData)赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
②指定初始容量(initialCapacity)构造器
initialCapacity为负数抛出异常
initialCapacity为0,将维护的数组(elementData)赋值为空集
initialCapacity为正数,将维护的数组(elementData)赋值为长度为initialCapacity的数组
②参数为Collection的构造器
1、通过参数获取新的数组赋值给维护的数组(elementData)
2、将size刷新并判断长度,为零则与new ArrayList(0)一样处理(将维护的数组(elementData)赋值为空集),不为零并且判断不是
Object[]类型,则变为Object[]类型。
3、常用方法
①public boolean add(E e)
//添加单个元素
public boolean add(E e) {
//确保容量够用
ensureCapacityInternal(size + 1);
//赋值
elementData[size++] = e;
return true;
}
//确保容量够用,参数是最小容量条件
private void ensureCapacityInternal(int minCapacity) {
//计算容量后确定容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//前面讲过,如果是空构造即new ArrayList(),就会赋值DEFAULTCAPACITY_EMPTY_ELEMENTDATA
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//默认容量与最小容量条件对比,返回大的
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//确定容量,参数是最小容量条件
private void ensureExplicitCapacity(int minCapacity) {
//添加、删除、修改等操作时,modCount的值就会增加,modCount主要目的就是用来限制用户在迭代时修改列表,造成数据错乱
modCount++;
//若计算的容量大于实际容量则扩容
if (minCapacity - elementData.length > 0
grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
// 现在维护的数组的容量
int oldCapacity = elementData.length;
// 新容量为之前的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 新容量若不够,使用需求容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 这里一定要用减法,不是直接比较大小(可以想新容量负数时)
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 扩容到指定大小
elementData = Arrays.copyOf(elementData, newCapacity);
}
②public void add(int index, E element)
public void add(int index, E element) {
//检查此下标是否存在
rangeCheckForAdd(index);
//确定容量
ensureCapacityInternal(size + 1);
//将index开始到最后的元素都向后复制到下一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//赋值
elementData[index] = element;
size++;
}
③其他方法
public E get(int index): 1、检查index是否合理 2、直接在维护的数组中查index 返回
public E remove(int index):1、检查index是否合理 2、通过System.arraycopy把index后面每个元素向前移动一位 3、把末尾赋值null,size减1
public E set(int index, E element): 1、检查index是否合理 2、直接在维护的数组对下标为index的元素赋值
由于过于简单,这里不再列举
三、总结
ArrayList底层是基于数组实现的,在new ArrayLIst()后容量是0,在添加第一个元素时会默认容量为10,扩容时默认扩容到原来的1.5倍。
ArrayList的扩容机制是通过拷贝数组实现的,删除某个元素是也要进行大量拷贝,所以插入元素或者删除某个元素时效率会很低,而在查询或者更新是效率很高。