参考阅读:ArrayList 源码分析
一、特点
ArrayList 继承于 AbstractList ,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口,具有以下特点:
- 支持添加,删除和查找操作
- 支持随机快速访问,即通过元素的序号快速读取元素
- 支持拷贝(深拷贝或浅拷贝)
- 支持序列化(对象转为字节流进行储存或网络传输)
二、扩容机制
- 以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。
- 调用add方法,默认追加到队尾,如果元素个数大于初始化的10,那么调用grow方法进行扩容。
- int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右(oldCapacity 为偶数就是 1.5 倍,否则是 1.5 倍左右)! 奇偶不同,比如:10+10/2 = 15, 33+33/2=49。如果是奇数的话会丢掉小数.
">>"(移位运算符):>>1 右移一位相当于除 2,右移 n 位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了 1 位所以相当于 oldCapacity /2。对于大数据的 2 进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源
三、特殊方法
1. System.arraycopy() 和 Arrays.copyOf() 方法
// 我们发现 arraycopy 是一个 native 方法,接下来我们解释一下各个参数的具体意义
/**
* 复制数组
* @param src 源数组
* @param srcPos 源数组中的起始位置
* @param dest 目标数组
* @param destPos 目标数组中的起始位置
* @param length 要复制的数组元素的数量
*/
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
public static int[] copyOf(int[] original, int newLength) {
// 申请一个新的数组
int[] copy = new int[newLength];
// 调用System.arraycopy,将源数组中的数据进行拷贝,并返回新的数组
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
看两者源代码可以发现 copyOf()内部实际调用了 System.arraycopy() 方法
arraycopy() 需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置。
copyOf() 是系统自动在内部新建一个数组,并返回该数组。
2. ensureCapacity()
我们可以看出向 ArrayList 添加大量元素之前使用ensureCapacity 方法可以提升性能。
四、注意
- 可以添加null值
- 不保证线程安全