Java之集合 - ArrayList源码分析

一、简介

上图为ArrayList的继承树,可看出实现了四个接口,分别介绍一下:

  • Serializable:是一个空接口,实现了该接口的类可序列化和反序列化
  • Cloneable:是一个空接口,实现该接口的类覆盖了clone()方法,表明该类的实例对象能被克隆
  • RandomAccess:是一个空接口,表明该类的实例对象支持随机访问
  • List:表明该类是一个列表,具有增加、删除、修改、遍历等功能

 

二、源码分析

1. ArrayList的属性

// 默认初始化容量为10
private static final int DEFAULT_CAPACITY = 10; 
// 空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {}; 
// 当使用默认初始化容量时创建的空数组实例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存放元素的数组
// 当 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 
// 将第一个元素存入ArrayList时该数组会扩容至容量为10
transient Object[] elementData;
// ArrayList的实际大小,即存放的元素数量
private int size;
// ArrayList允许存放的最大元素数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2. 构造方法

// 默认构造函数,使用默认初始化容量10,存放元素的数组指向一个空数组,
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);
	}
}

// 传入一个集合
public ArrayList(Collection<? extends E> c) {
	elementData = c.toArray();
	if ((size = elementData.length) != 0) { 
		// 集合非空时则将集合的元素复制至数组
		if (elementData.getClass() != Object[].class)
			elementData = Arrays.copyOf(elementData, size, Object[].class);
	} else {
		// 传入的集合为空时指向一个空数组
		this.elementData = EMPTY_ELEMENTDATA;
	}
}

3. 增加元素

// 将元素添加到数组末尾
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // 判断是否需要扩容,后面详细讲
	elementData[size++] = e;
	return true;
}

// 将元素添加到指定位置
public void add(int index, E element) {
	rangeCheckForAdd(index); // 检查是否越界

	ensureCapacityInternal(size + 1); 
	System.arraycopy(elementData, index, elementData, index + 1,
					 size - index); // 将index开始的元素向后移一位
	elementData[index] = element;
	size++;
}

// 将集合所有元素添加至列表末尾
public boolean addAll(Collection<? extends E> c) {
	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacityInternal(size + numNew);  // Increments modCount
	System.arraycopy(a, 0, elementData, size, numNew);
	size += numNew;
	return numNew != 0;
}

// 将集合元素添加至指定位置
public boolean addAll(int index, Collection<? extends E> c) {
	rangeCheckForAdd(index);

	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacityInternal(size + numNew);  // Increments modCount

	int numMoved = size - index;
	if (numMoved > 0)
		System.arraycopy(elementData, index, elementData, index + numNew,
						 numMoved);

	System.arraycopy(a, 0, elementData, index, numNew);
	size += numNew;
	return numNew != 0;
}

5. 删除元素

// 将指定位置的元素删除
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; 

	return oldValue;
}

// 删除指定元素
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;
}

// 删除指定范围的元素
protected void removeRange(int fromIndex, int toIndex) {
	modCount++;
	int numMoved = size - toIndex;
	System.arraycopy(elementData, toIndex, elementData, fromIndex,
					 numMoved);

	int newSize = size - (toIndex-fromIndex);
	for (int i = newSize; i < size; i++) {
		elementData[i] = null;
	}
	size = newSize;
}

// 删除数组中与集合相等的元素
public boolean removeAll(Collection<?> c) {
	Objects.requireNonNull(c); // 检查集合是否为null
	return batchRemove(c, false);
}

// 按指定条件删除元素
@Override
public boolean removeIf(Predicate<? super E> filter) {
	Objects.requireNonNull(filter);
	
	int removeCount = 0; // 删除元素的个数
	final BitSet removeSet = new BitSet(size); // 记录删除元素的位置
	final int expectedModCount = modCount;
	final int size = this.size;
	for (int i=0; modCount == expectedModCount && i < size; i++) {
		@SuppressWarnings("unchecked")
		final E element = (E) elementData[i];
		if (filter.test(element)) { // 检验元素是否符合删除条件
			removeSet.set(i); // 将符合条件的元素在removeSet中对应的位置置true
			removeCount++;
		}
	}
	if (modCount != expectedModCount) {
		throw new ConcurrentModificationException();
	}

	final boolean anyToRemove = removeCount > 0; // 是否有元素被删除
	if (anyToRemove) { // 若为true则将数组中符合条件的元素删除
		final int newSize = size - removeCount;
		for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
			i = removeSet.nextClearBit(i); 
			elementData[j] = elementData[i];
		}
		for (int k=newSize; k < size; k++) {
			elementData[k] = null;
		}
		this.size = newSize;
		if (modCount != expectedModCount) {
			throw new ConcurrentModificationException();
		}
		modCount++;
	}

	return anyToRemove;
}


// 删除所有元素
public void clear() {
	modCount++;

	for (int i = 0; i < size; i++)
		elementData[i] = null;

	size = 0;
}

6. 修改元素

// 修改指定位置的元素,并返回旧值
public E set(int index, E element) {
	rangeCheck(index);

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

7. 获取元素

// 获取指定位置的元素
public E get(int index) {
	rangeCheck(index);

	return elementData(index);
}

E elementData(int index) {
	return (E) elementData[index];
}

8. 扩容机制

// 当尝试增加一个元素时,会调用该函数
private void ensureCapacityInternal(int minCapacity) {
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 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++;

	// 若增加元素后数组大小大于原数组大小则需要扩容
	if (minCapacity - elementData.length > 0)
		grow(minCapacity);
}


// 扩容至原数组大小的1.5倍
private void grow(int minCapacity) {
	int oldCapacity = elementData.length;
	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);
}

private static int hugeCapacity(int minCapacity) {
	if (minCapacity < 0) // 上溢
		throw new OutOfMemoryError();
	return (minCapacity > MAX_ARRAY_SIZE) ?
		Integer.MAX_VALUE :
		MAX_ARRAY_SIZE;
}
  1. 计算增加元素后元素的个数:当增加元素时,会先调用方法计算增加元素后元素的个数,分为两种情况,若数组为空则取初始化容量和增加元素后元素个数的最大值,否则直接返回增加元素后元素个数
  2. 判断是否扩容:根据返回值,如果大于当前数组的容量则需要扩容
  3. 扩容:新的容量为原来的1.5倍,若该值小于元素个数则新容量更改为元素个数,若大于MAX_ARRAY_SIZE则取Integer允许的最大值和MAX_ARRAY_SIZE的最大值,若小于0即上溢,抛出异常
  4. 复制元素至扩容后的数组
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章