容器(二)ArrayList源码解析
概述:ArrayList底层由Object[]组成,按照存储顺序访问元素,线程不安全,每个ArrayList都有默认的容量(capacity),当存储元素超过某个阈值时,进行扩容。
ArrayList组成
- 成员变量
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//对象数组
transient Object[] elementData; // non-private to simplify nested class access
//元素个数
private int size;
-
构造方法
//无参构造,空数组 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); } } //将外部集合转化为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; } }
-
扩容方法
每次add()时,会进行判断,当前元素个数size是否和capacity满足关系,进行扩容1.5倍,首先计算需要扩充的容量,然后创建该容量数组,最后进行复制,成为新的ArrayList。因为扩容需要消耗资源,可以在创建或者调用ensureCapacity(int)手动增加容量
重要方法
Arrays.copyOf(original,newlength)//创建newlength长度数组 b //将源数组 original 拷贝到目标数组 b //复制方法 System.arraycopy 调用底层实现 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
``
复杂的扩容方式:
指定位置index add/addAll(index,Collection)
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
//插入元素
Object[] a = c.toArray();
//插入元素个数
int numNew = a.length;
//扩容,创建新数组,元素按照原来位置排放
ensureCapacityInternal(size + numNew); // Increments modCount
//需要后移元素个数,也称为移动次数
int numMoved = size - index;
if (numMoved > 0)
//将需要移动元素进行移动,从index位置,移动到index+numNew位置,移动 numMoved次
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//完后,再次复制,将插入元素从头开始,复制到目标数组,从index位置,移动numNew次
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
- 其他方法
get(index):获取指定位置元素
E elementData(int index) {
return (E) elementData[index];
}
set(index,e):修改指定位置元素值
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
remove(index):删除指定位置元素
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; // 元素为空,为了让GC回收
return oldValue;
}
remove(obj):删除第一个满足元素值为Obj位置元素
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;
}
}
private void fastRemove(int index) {
modCount++;
//因为是删除,故移动个数-1
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
}