集合框架 — ArrayList
一、结构特点
- 底层是数组实现,存放对象(基本类型则存放对应的包装类型)
- 可以存放任意数量对象,动态扩容
- 查询效率高,增删效率低,线程不安全
二、ArrayList初始化
注意:在通过构造方法对ArrayLis初始化时,赋值的是一个空数组,数组容量这时候不是10
当对数组添加数据时,才会分配默认的初始容量值 10
1、无参构造
构造一个空数组
// 初始化赋值一个默认的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2、有参构造
根据传入参数的值,进行不同的操作
private static final int DEFAULT_CAPACITY = 10;
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 参数大于0,初始容量为参数值
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 参数等于0,初始一个空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 小于0,报错
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
三、ArrayList扩容
-
定义一个长度为原数组
1.5倍
长度的数组// 1.7的时候为: 5/2+1 1.8改为:5/2,在新增操作会判断下要不要扩容 int newCapacity = oldCapacity + (oldCapacity >> 1);
-
将原数组数据,直接复制到新数组中
-
将ArrayList地址换成新数组的
四、ArrayList添加数据
1、不指定位置 add()
先确保数组容量,无需扩容则直接添加到数组最后
public boolean add(E e) {
// 确保内部容量
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
2、指定位置添加 add(int, E)
- 确保添加范围,和数组容量正常
- 拷贝数组,将所需添加位置后面的全部数据向后移动(ArrayList增删慢的原因)
- 将数据添加到指定位置
3、删除操作
- 也和指定位置新增元素一样,也是拷贝数组,就是将需要删除元素位置后面的数组向前覆盖
五、ArrayList的使用和安全性
1、线程安全性
- ArrayList 不是线程安全的
- 线程安全版本的数组容器是
Vector
,实现原理就是ArrayList所有方法加上synchronized
2、使用场景
-
ArrayList 不适合做队列
因为队列是FIFO(先进先出),如果用ArrayList做队列,需要在ArrayList数组尾加数据(速度快),数组头删除数组(很慢),而数组很适合做队列(定长)
-
遍历性能
ArrayList读操作性能很快,因为存储的内存都是连续的,CPU的内部缓存结构会缓存连续的内存片段,而且数组通过下标查找,时间复杂度也是O(1)