ArrayList原理和源码分析
集合ArrayList的原理和源码
ArayList是java的一个集合类,实现了List接口。应用非常广泛,数据库查询结果集、excel导入解析、json数据解析,网站数据爬虫解析等等都会使用到。
1.创建
//创建一个空的数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_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);
}
}
2.主要的属性
/**
* Default initial capacity.
默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
用于共享一个空的数据实例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
* 集合的长度
* @serial
*/
private int size;
3.add()
//append 一个元素到list的末尾
public boolean add(E e) {
//第一次add时会初始化Object[]
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
核心方法ensureCapacityInternal(size + 1);
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//方法是返回数组的下标
//1.如果第一次创建,则会返回DEFAULT_CAPACITY
//2.如果不是第一次创建,则返回当前的下标
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)
grow(minCapacity);
}
grow(minCapacity)
//扩容的计算
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容1.5倍,oldCapacity >> 1是取原来数组长度的一般,在加上原来的长度,即1.5倍,
//注意5>>1的值为2
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//此处判断当要扩容的长度大于MAX_ARRAY_SIZE时的一些判断,具体看代码
//
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);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//超过MAX_ARRAY_SIZE,就返回Integer的最大值,否则就是minCapacity
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
4.其他的一些方法
4.1contains(e)
//真正调用的是indexOf(o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
//其实都是用的for循环去判断数组中有没有包含这个元素,分为了2中情况,o=null和o!=null
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;
}
4.2 set(int index, E element)
//其实就是对已有元素的一个更新赋值,并返回原来的值
public E set(int index, E element) {
//检查当前出入的index是否符合规范,如果查过当前数组长度,则会抛出IndexOutOfBoundsException
rangeCheck(index);
//拿到index下标的元素,然后进行更新赋值,同时返回原来的值
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
4.3 get(int index)
//检查index,然后返回元素,这就是数组的查询效率
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
4.4remove(int index)
//删除对应下标的元素并返回
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//计算要copy的数据的长度
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;
}
4.5 remove(Object o)
//根据o先查找到数据所在的下标,然后再调用fastRemove方法,删除的逻辑和上文的一致
//次方法返回的是boolean类型
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;
}
4.6size()
//在每次add或者remove的时候会对size的值有一个维护,
public int size() {
return size;
}
4.7isEmpty()
public boolean isEmpty() {
return size == 0;
}
4.8clear()
//将数组的每一个元素置位null,并将size设置为0
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
4.9addAll()
求2个集合的并集
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//这里是对数组的一个扩容
ensureCapacityInternal(size + numNew); // Increments modCount
//2个list的数据合并,通过数组的一个copy
System.arraycopy(a, 0, elementData, size, numNew);
//合并完成后list 的集合长度等于2个list的和
size += numNew;
return numNew != 0;
}
4.10retainAll()
求2个集合的交集
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
//真正执行的方法,注意这里的一个参数,当参数为true时是获取交集,当参数为false时,是获取差集
return batchRemove(c, true);
}
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
//核心代码,就是这里去判断是否了目标预算, 如果包含则是属于交集,如果不包含则是差集。
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//此处是在c.congtains()发生了异常,则这时的r!=size,就需要将r以后的数据直接拷贝到 //elementData中,并计算w的值
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
//如果w!=size,说明2个集合中存在不同的元素,则需要将w下标之后的数据置位null
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
4.11removeAll()
求2个集合的差集
//具体参见上面的batchRemove方法
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
4.12无重复并集
list2.removeAll(list1);
list1.addAll(list2);