- ArrayList 是最常用的 List 实现类,它适合随机查找和遍历,但不适合插入和删除。
- Vector 和 ArrayList 一样,但Vector 不支持线程同步,但线程安全,ArrayList 线程不安全
ArrayList 非线程安全,底层是一个 Object[ ] ,添加到ArrayList中的数据保存在了elementData属性中。所以 ArrayList 具有数组的查询速度快的优点以及增删速度慢的缺点。
- 当调用
new ArrayList<>()
时,将一个空数组{}赋值给了 elementData,这个时候集合的长度size为默认长度0; - 当调用
new ArrayList<>(100)
时,根据传入的长度,new一个Object[100]赋值给 elementData,当然如果玩儿的话,传了一个0,那么将一个空数组{}赋值给了elementData; - 当调用 new ArrayList<>(new HashSet()) 时,根据源码,我们可知,可以传递任何实现了Collection接口的类,将传递的集合调用 toArray() 方法转为数组内赋值给elementData;
ArrayList常用方法
ArrayList有很多常用方法,add,addAll,set,get,remove,size,isEmpty等
add(E element)
public boolean add(E e) {
ensureCapacityInternal(size + 1);
// Increments modCount!!
elementData[size++] = e;
return true;
}
首先通过 ensureCapacityInternal(size + 1)
来保证底层 Object[ ] 数组有足够的空间存放添加的数据,然后将添加的数据存放到数组对应的位置上,我们看一下是怎么保证数组有足够的空间?
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity); // 数组扩容
}
首先确定 Object[] 足够存放添加数据的最小容量,然后通过 grow(int minCapacity)
来进行数组扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
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);
}
扩容规则为⚠️:数组当前足够的最小容量 * 1.5,有最大值限制。
set(int index, E element)
由于 ArrayList 底层由数组实现,set实现非常简单,
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
get(int index)
ArrayList 中 get 方法也非常简单,通过下表查找即可,前提是需要判断传入的数组下标是否越界。
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
remove(int index)
首先获取待删除的元素,并最终返回。其次计算了需要移动的位数 size - index - 1,然后将原本位置的元素设为 null
public E remove(int index) {
rangeCheck(index); // 判断数组越界
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
remove(Object o)
删除 ArrayList 中的值对象,其实和通过下标删除很相似,遍历底层数组 elementData ,通过 equals() 方法或 == (特殊情况)来找到要删除的元素,获取其索引值,一样的方式删除
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
其他方法
size() : 获取集合长度,通过定义在ArrayList中的私有变量size得到
isEmpty():是否为空,通过定义在ArrayList中的私有变量size得到
contains(Object o):是否包含某个元素,通过遍历底层数组elementData,通过equals或==进行判断
clear():集合清空,通过遍历底层数组elementData,设置为null