在list集合中,ArrayList是最为常见的。通过了解底层代码来进一步了解ArrayList。
一、ArrayList的继承关系与属性
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
继承关系:可以看到ArrayList继承的是抽象类AbstractList类,同时实现了list(规定了List的操作规范)等接口。
RandomAccess:表示可以随机访问
Cloneable:可以clone
Serializable:实现了序列化接口,可以将实现了Serializable接口的对象转换
为字节序列
属性:
// 缺省容量
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素数组,使用关键字transient 避免被序列化
transient Object[] elementData;
// 实际元素大小,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
二、构造方法
//无参构造函数,给定一个默认的空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//通过判断传入值的大小,来初步确定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);
}
}
传入的是集合类型:先转化为数组类型,然后判断数组类大小,同时给elementData赋值
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) //是否转化为Object数组
elementData = Arrays.copyOf(elementData, size, Object[].class); //没有转化就复制
} else { //如果是空集合,则直接赋值空数组
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
三、常用API
1.add(E e)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
执行add()第一步是执行ensureCapacityInternal(size + 1);可以看做是确定集合长度,即保证elementData有足够大大小。
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断数组是否为空
return Math.max(DEFAULT_CAPACITY, minCapacity);//为空,则返回最大值
}
return minCapacity;//否则,返回最小值
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//当返回d的最小值大于数组的长度时候,执行下列方法,对数组进行扩容
grow(minCapacity);
}
扩容的具体过程
private void grow(int minCapacity) {
int oldCapacity = elementData.length; // 旧容量
int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量为旧容量的1.5倍
if (newCapacity - minCapacity < 0) // 新容量小于参数指定容量,修改新容量
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) // 新容量大于最大容量
newCapacity = hugeCapacity(minCapacity); // 指定新容量
// 拷贝扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
2.add(int index, E element) 指定位置添加数据
public void add(int index, E element) {
rangeCheckForAdd(index); //检查指定位置是否合理
ensureCapacityInternal(size + 1); // 同理于add()方法
System.arraycopy(elementData, index, elementData, index + 1,
size - index); //采用System复制进行数据插入,同时看数据是否需要移位
elementData[index] = element;
size++;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// System.arraycopy 解析
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
Object src : 原数组
int srcPos : 从元数据的起始位置开始
Object dest : 目标数组
int destPos : 目标数组的开始起始位置
int length : 要copy的数组的长度
3.remove(int index)
public E remove(int index) {
rangeCheck(index); //检查下标的合理性
modCount++;
E oldValue = elementData(index); //得到下标对应的值
int numMoved = size - index - 1; //数组长度-1,判断数据是否需要左移
if (numMoved > 0) //执行arraycopy
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
//数组最后一个置null,方便系统GC回收
return oldValue;
}
4.clear() 数组置为空,同时系统是调动GC进行回收
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
5.indexOf(Object o)
public int indexOf(Object o) {
if (o == null) { //说明了数组中可以存在null值
for (int i = 0; i < size; i++)
if (elementData[i]==null) //找到第一个就直接返回
return i;
} else { //如果不是null值
for (int i = 0; i < size; i++) // 遍历数组,找到第一个和指定元素相等的元素,返回下标
if (o.equals(elementData[i]))
return i;
}
return -1; //没有的话,则返回-1
}
6.set(int index,E e)
public E set(int index, E element) {
rangeCheck(index); //检查合法性
E oldValue = elementData(index);
elementData[index] = element; //用传入的值覆盖原来d的值
return oldValue; //返回旧值
}
四、总结:
ArrayList底层是利用数组实现,可以存在null
ArrayList在查询时候比较方便,但是插入的话,从add(int index, E element)可以看出需要移动大量元素,效率不怎么高
ArrayList在使用for循环和foreach进行数据迭代时候,效率是差不多