ArrayList源码学习
ArrayList继承关系
public class ExtArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
它继承于 AbstractList 的UML图:
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandomAccess 接口, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
ArrayList 实现了Cloneable 接口,即覆盖了函数 clone(),能被克隆。
ArrayList 实现java.io.Serializable 接口,这意味着ArrayList支持序列化,能通过序列化去传输。
ArrayList实现原理
内部是使用数组,进行存储数据
默认初始容量为10,以10 + 10>>1的大小扩容
使用System.arraycopy()方法进行扩容
ArrayList remove方法也是通过System.arraycopy()方法实现,移动元素之后,将最后一个元素置为null
remove删除对象,通过for循环,将全部数组元素遍历,使用equals判断对象是否相等,然后调用remove(int index)方法将对象删除
/**
* 添加元素方法
*/
public boolean add(E e) {
//判断是否需要进行扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* 判断是否需要进行扩容
* @param minCapacity
*/
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
* 判断是否可以进行扩容
* @param minCapacity
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//如果最小容量比原数组容量大,进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 扩容数组方法
*
* @param minCapacity 自定义最小容量大小
*/
private void grow(int minCapacity) {
// 原数组大小
int oldCapacity = elementData.length;
//获取新的容量大小,使用位移算法 >>
int newCapacity = oldCapacity + (oldCapacity >> 1);
//这一步是防止原数组容量为空或者为1,然后新的容量大小计算出错
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新的容量大小超过了数组的最大容量大小,则使用数组的最大容量大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用扩容方法
elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
* 删除数组元素方法
* @param 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);
//将最后一个元素赋值为null,为了让GC回收
elementData[--size] = null;
return oldValue;
}
/**
* 检查下标是否超过数组元素大小
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* 获取指定下标元素
* @param index 下标
*/
public E get(int index) {
//判断下标是否越界
rangeCheck(index);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
Arraylist扩容机制
System.arraycopy() 与Arrays.copyOf()的区别
ArrayList底层是使用Arrays.copyOf()方法实现扩容
/**
* @param src 源数组
* @param srcPos 源数组的拷贝起点位置
* @param dest 目标数组
* @param destPos 放入没有标数组的起点位置
* @param length 需要拷贝源数组长度
* /
System.arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
Arrays.copyOf()底层是使用System.arraycopy()方法实现
copyOf方法在内部新建一个Object[]数组,将数组扩容后的值赋值给新数组
/**
* @param original 需要被拷贝的数组
* @param newLength 新数组的长度
* @param newType 拷贝的数组的返回值类型
*/
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;
}
ArrayList和Vector区别
扩容容量的大小不同
//Vector
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
//ArrayList
int newCapacity = oldCapacity + (oldCapacity >> 1);
ArrayList线程不安全
Vector给需要修改值的方法加上了synchronized关键字。