ArrayList源码、实现源码
属性:
//用于序列化的id
private static final long serialVersionUID = 8683452581122892189L;
//默认构造方法的容量
private static final int DEFAULT_CAPACITY = 10;
//空数组,构造方法中参数为0时使用--->new ArrayList(0)
private static final Object[] EMPTY_ELEMENTDATA = {};
//空数组,默认构造方法使用--->new ArrayList()
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//临时存放元素的数组,使用transient修饰,不会被序列化
transient Object[] elementData;
//元素实际个数
private int size;
//数组能分配的最大内存,超出会OutOfMemoryError
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
构造方法:
//构造方法一,传入容量
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);
}
}
//构造方法二,不传入初始容量
public ArrayList() {
//当添加第一个元素时,扩容到默认大小10
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//构造方法三,传入一个集合,将其转化为ArrayList
public ArrayList(Collection<? extends E> c) {
//集合转数组
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 检查c.toArray()返回的是不是Object[]类型,如果不是,重新拷贝成Object[].class类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 如果c的空集合,则初始化为空数组EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList的add(E e)方法:
大致思路: 首先判断是否需要扩容,先需要计算该集合的容量,如果这个集合是空集合的话,给定默认的容量为10,如果不是空集合的话再进行扩容,新容量的大小为原容量的1.5倍。如果新容量的大小小于需要容量,则以需要容量为准。如果新容量的大小大于最大容量,则以最大容量为准,最终实现数组的拷贝。
public boolean add(E e) {
// 检查是否需要扩容
ensureCapacityInternal(size + 1);
// 把元素插入到最后一位
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果是空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,就初始化为默认大小10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
// 扩容
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新容量发现比需要的容量还小,则以需要的容量为准
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新容量已经超过最大容量了,则使用最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 以新容量拷贝出来一个新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
add(int index, E element)方法
public void add(int index, E element) {
//检查是否越界
rangeCheckForAdd(index);
//检查是否需要扩容
ensureCapacityInternal(size + 1);
//将index及其后的元素向后移动一位,空出index的位置
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//空出的位置存放加入的元素
elementData[index] = element;
//数量加一
size++;
}
addAll(Collection<? extends E> c)方法
public boolean addAll(Collection<? extends E> c) {
//集合转为数组
Object[] a = c.toArray();
int numNew = a.length;
//检查扩容
ensureCapacityInternal(size + numNew);
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
get(int index)方法
public E get(int index) {
// 检查是否越界
rangeCheck(index);
// 返回数组index位置的元素
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
return (E) elementData[index];
}
remove(int index)方法
public E remove(int index) {
// 检查是否越界
rangeCheck(index);
modCount++;
// 获取index位置的元素
E oldValue = elementData(index);
// 如果index不是最后一位,则将index之后的元素往前挪一位
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
// 将最后一个元素删除,帮助GC
elementData[--size] = null; // clear to let GC do its work
// 返回旧值
return oldValue;
}
总结
(1)ArrayList内部使用数组存储元素,当数组长度不够时进行扩容,每次加一半的空间,ArrayList不会进行缩容;
(2)ArrayList支持随机访问,通过索引访问元素极快,时间复杂度为O(1);
(3)ArrayList支持求并集,调用addAll(Collection<? extends E> c)方法即可;
(4)ArrayList支持求交集,调用retainAll(Collection<? extends E> c)方法即可;
(5)ArrayList支持求单向差集,调用removeAll(Collection<? extends E> c)方法即可;
(6)ArrayList有两种迭代器,支持向前向后遍历。
(7)ArrayList底层基于数组,所以除了迭代器,也可以使用循环遍历。
(8)ArrayList查询快,增删慢,线程不安全。
ArrayList查询快的原因是因为底层是数组,只需要获取数组下标即可获得元素,对于增删慢的原因是因为ArrayList是需要移动元素,导致增删慢。
还没有评论,来说两句吧...