目录
简介
Arraylist在java基础集合框架中是非常常用的一个数据结构,ArrayList实现了List接口,继承了AbstractList类,底层基于数组数据结构,实现自由扩容,实现了Cloneable接口覆盖了函数clone()完成克隆,RandomAccess,Serializable接口
特性
ArrayList底层就是一个数组
优点:查询效率快
缺点:增删效率慢(扩容需要重新创建新的数组)
方法解析
底层结构
源码解析
demo主函数分四个步骤
public static void main(String[] args) {
// 第一步 创建一个ArrayList集合
ArrayList arrayList = new ArrayList();
for (int i = 0; i < 10; i++) {
//第二步 第一次添加一个元素时
arrayList.add(i);
}
// 第三步 添加第11个数据
arrayList.add(11);
List removeArr = new ArrayList<>();
removeArr.add(1);
// 第四步 移除一个元素
arrayList.removeAll(removeArr);
}
第一步: 创建一个ArrayList集合时,会初始化一个DEFAULTCAPACITY_EMPTY_ELEMENTDATA为空数组
/**
* 使用构造方法时,创建一个空数组赋值
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
第二步:添加一个元素
public boolean add(E e) {
// size为数组的长度
ensureCapacityInternal(size + 1); // Increments modCount!!
// e 为要赋值的值
elementData[size++] = e;
return true;
}
/**
* 初始化数组长度
*/
private static final int DEFAULT_CAPACITY = 10;
// minCapacity 添加元素后数组的长度
private void ensureCapacityInternal(int minCapacity) {
// 第一次添加元素时,此条件满足且都为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// DEFAULT_CAPACITY = 10 ,minCapacity = 1
// minCapacity = 10 赋值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
// 修改次数
modCount++;
// 判断加入元素后数组的大小是否需要扩容
// 10 - 0 > 0 需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 数组的最大长度
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 最小的长度实际为添加元素后 元素的数量
* 旧数组长度为,添加元素前的数组长度
* 新数组长度为扩容之后的长度
*/
private void grow(int minCapacity) {
// 给旧数组的长度赋值 此处第一次添加为0
int oldCapacity = elementData.length;
// 给新数组的长度赋值 oldCapacity >> 1 实际上newCapacity为 oldCapacity的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 判断最新的长度是否小于旧的数组长度,如果小于,则将最小的长度赋值给新的长度
// 1 - 10 < 0 newCapacity = 10; 新的数组长度为10
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新容量大于数组的最大长度,使用hugeCapacity比较二者
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 将旧的数组复制到新的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
第三步:添加第11个元素时,当添加元素到10个以上时,按照上面步骤一样,扩容之后的值为10 + 10*1/2 为 15 ,扩容之后的新的数组大小为15;
int newCapacity = oldCapacity + (oldCapacity >> 1);
第四步: 移除集合中的元素
public boolean retainAll(Collection<?> c) {
// 校验参数是否为null,如果为空则报空指针异常,否则放行
Objects.requireNonNull(c);
return batchRemove(c, false);
}
/**
* 移除集合中的元素 complement为false时,原集合移除参数集合中的数据
* complement为true时,原集合只留参数集合中包含的元素
*/
private boolean batchRemove(Collection<?> c, boolean complement) {
// complement 为false
// 新增一个elementData数组赋值,为移除后数据的容器
final Object[] elementData = this.elementData;
// 新建两个变量,r为读取数组时的索引,w为写入时数组的索引
int r = 0, w = 0;
// 返回的值
boolean modified = false;
try {
for (; r < size; r++)
// 判断是否包含元素集合中的数据
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
for (int i = w; i < size; i++)
// 赋值为null,用于GC回收,对象不被引用
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
数组和ArrayList的有哪些不同?
- ArrayList是可以自由扩容的
- ArrayList是类型安全的(编译不报错),因为有泛型,所以存储任何泛型类型数据,数组只能存储一种
- 获取长度的方法不同,arraylist获取长度的方法是size(),数组获取长度方法为length()