您的位置:首页 > 编程语言 > Java开发

源码学习之ArrayList

2016-05-26 10:07 363 查看

ArrayList源码分析学习

首先是ArrayList的定义

//继承AbstractList抽线类,实现了List、RandomAccess、Cloneable和Serializable接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable


ArrayList源码开头定义的几个成员变量

//表示ArrayList的默认容量为10,但是在我们初始化为一个空的ArrayList的时候容量并不是10,具体下文解释
private static final int DEFAULT_CAPACITY = 10;
//表示空的一个元素数组,在初始化一个空的ArrayList的时候,elementData就等于这个EMPTY_ELEMENTDATA
private static final Object[] EMPTY_ELEMENTDATA = {};
//这个就是实际存储数据的数组,从这个可以看出ArrayList是数组实现的
transient Object[] elementData;
//这个就是数组列表的存储数据的size了
private int size;


构造函数,ArrayList一共提供了三个构造函数。

//第一个构造函数,参数initialCapacity为初始化容量,如果initialCapacity为负,则抛出IllegalArgumentException异常,否则就初始化elementData为一个大小为initialCapacity的数组
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
this.elementData = new Object[initialCapacity];
}
//第二个构造函数,不传入参数,这个时候elementData,就设置成上文定义的空数组,EMPTY_ELEMENTDATA,这个时候数组链表的容量是0,并不是10.
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
//第三个构造函数,传入参数为另一个集合。这个时候就是用传入集合的元素初始化数组链表。
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}


ArryList扩容机制

//保证容量,这块是外部手动调用扩容的。minCapacity是需要的最小容量。
public void ensureCapacity(int minCapacity) {
//最小扩展,如果elementData等于EMPTY_ELEMENTDATA,那么minExpand设置为DEFAULT_CAPACITY,否则minExpand等于0
int minExpand = (elementData != EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
//如果最小需要容量大于最小扩展,那么这个时候需要保证最小需要容量的数值
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}


//保证容量,这是内部函数调用用来扩容的,在每次添加元素的时候都会调用
private void ensureCapacityInternal(int minCapacity) {
//elementData == EMPTY_ELEMENTDATA时,这个时候minCapacity去DEFAULT_CAPACITY和minCapacity大的一个。
//在初始化一个空的ArrayList时,elementData == EMPTY_ELEMENTDATA,这个时候添加一个元素,检查容量,minCapacity传递的是size+1,也就是1,这个时候minCapacity等于DEFAULT_CAPACITY。
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}

ensureExplicitCapacity(minCapacity);
}


//上面两个函数调用的函数
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//如果需要保证的最小容量大于elementData的长度,那么这个时候需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}


private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//具体的扩容函数
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//新容量,是原来的容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量不能满足最小容量要求,那么新容量设置成minCapacity
//从空添加一个元素的时候,minCapacity==DEFAULT_CAPACITY,这个时候容量就扩充到DEFAULT_CAPACITY了。
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新容量大于MAX_ARRAY_SIZE,那么新容量设置成Integer.MAX_VALUE
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);
}


//如果minCapacity大于MAX_ARRAY_SIZE,那么返回
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}


总结来说,扩容的机制是在每次添加元素的时候检查容量size+add_size,elementData是空数组的时候,容量会变成DEFAULT_CAPACITY,也就是10。elementData不是空数组的时候,如果size+add_size大于容量,也即是elementData.length,那么就扩容,扩容的方法是首先扩容1.5倍的原容量,然后判断1.5的原容量是否大于size+add_size,如果不大于,那么新容量设置成size+add_size,再检查size+add_size是否大于最大容量Integer.MAX_VALUE - 8,如果大于那么就设置成Integer.MAX_VALUE

ArrayList常用操作

size()

public int size() {
return size;
}


isEmpty()

public boolean isEmpty() {
return size == 0;
}


contains()

public boolean contains(Object o) {
return indexOf(o) >= 0;
}
//找到elementData中第一次出现o的下标
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;
}


get()

public E get(int index) {
//是否越界判断
rangeCheck(index);

return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}


set()

//修改下标index处的元素
public E set(int index, E element) {
rangeCheck(index);

E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}


add()

//在后面添加一个元素
public boolean add(E e) {
//判断容量
ensureCapacityInternal(size + 1);  // Increments modCount!!
elementData[size++] = e;
return true;
}
//在下标index处添加一个元素,有数据的移动
public void add(int index, E element) {
rangeCheckForAdd(index);

ensureCapacityInternal(size + 1);  // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}


remove()

//删除下标为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);
elementData[--size] = null; // clear to let GC do its work

return oldValue;
}
//删除赌徒个等于o的元素
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;
}


clear

public void clear() {
modCount++;

// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;

size = 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息