JDK1.8源码阅读之java.util.ArrayList
文章目录
构造器方法
无参构造器
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
// 将elementData数组初始化为空。
// 这里是惰性扩容,当要往数组中插入元素时,才会初始化扩容成默认长度10。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造器
private static final Object[] 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方法
步骤:
- 将插入的基础数据类型进行包装,比如int转换成Integer
// 这里的cache是一个数组,int类型的范围[-128,127] // cache[0]=-128 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
- 插入数据前需要确保数组容量充足
private int size; transient Object[] elementData; // non-private to simplify nested class access // 通过ensureCapacityInternal方法检查容量是否充足,如果不足就进行扩容 // size则是ArrayList对象维护的一个成员变量 public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } // 在某个索引处添加元素。 // 将index以及其后的所有元素向后移动一格 public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } // elementData 则是ArrayList对象的数据 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
- 计算需要的容量
private static final int DEFAULT_CAPACITY = 10; // 这个方法同时传入了elementData数组与minCapacity,考虑了数组是空的情况。 // 如果ArrayList才刚初始化,没有插入过数据,会直接扩容成DEFAULT_CAPACITY,也就是10 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
- 检查是否需要扩容
protected transient int modCount = 0; // modeCount是在每次修改ListArray都需要+1的,目的是为了在迭代器中确保其不被改动 // 逻辑:如果当前需要的最小容量小于elementData数组的长度就不需要扩容了 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
- 扩容
继续执行步骤2中的size++,并将元素放入到数组中,返回true// 每次扩容为原容量的1.5倍,并重开一个这么大容量的数组,将数据拷贝进去。 // 数组地址与原来的不同了 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 考虑到初始化的问题,未插入过元素的数组的长度为0 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); }
remove方法
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
// 遍历查询到该元素,之后执行与上一个remove相似的操作。但是这里就不需要check索引了
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
}
contians方法与indexOf方法
// 返回的是boolean,是否含有某个元素
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
// 循环遍历数组,如果有相同的就返回索引
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
// 倒序遍历
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
clone方法
// 浅拷贝,元素本身并不会被拷贝。因此如果数组元素时对象,且如果在v中改变元素,原数组内的元素也会发生改变
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
trimToSize方法
// 为了节省空间,可以让数组变成适合他的大小。
// 比如初始化了10,但是只用了5的情况。
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
最大容量
// 因为虚拟机中会有头部信息,因此最大容量是Integer.MAX_VALUE-8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;