ArrayList源码分析,你需要知道的所有知识点!("ArrayList源码详解:掌握必备核心知识点!")
原创
一、ArrayList简介
ArrayList是基于动态数组的数据结构,实现了List接口,可以动态地扩展容量。它是Java集合框架中非常常用的一个部分,具有查询快、插入慢的特点。本文将深入分析ArrayList的源码,帮助大家掌握其中的核心知识点。
二、ArrayList的重点构造方法
ArrayList提供了多个构造方法,以下是三个重点的构造方法:
public ArrayList(int initialCapacity) {
if (initialCapacity >= 0) {
this.elementData = new Object[initialCapacity];
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[]
// array with enough room
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
三、ArrayList的核心成员变量
ArrayList的核心成员变量如下:
transient Object[] elementData; // 非私有,以便于继承类访问
private int size; // 实际存储元素的数量
private static final Object[] EMPTY_ELEMENTDATA = {}; // 空数组
private static final int DEFAULT_CAPACITY = 10; // 默认容量
四、ArrayList的扩容机制
ArrayList的扩容机制是其核心特性之一。当数组空间不足以存储更多元素时,ArrayList会自动扩容。以下是扩容的核心方法:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// oldCapacity为旧容量,newCapacity为新容量
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);
}
五、ArrayList的添加元素方法
ArrayList提供了多种添加元素的方法,以下是一些常用的添加方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element;
size++;
}
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();
int numberOfNewElements = a.length;
ensureCapacityInternal(size + numberOfNewElements); // Increments modCount
System.arraycopy(a, 0, elementData, size, numberOfNewElements);
size += numberOfNewElements;
return numberOfNewElements != 0;
}
六、ArrayList的删除元素方法
ArrayList的删除元素方法相对较少,以下是常用的删除方法:
public E remove(int index) {
if (index >= size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) 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;
}
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;
}
private void fastRemove(int index) {
modCount++;
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
}
七、ArrayList的遍历方法
ArrayList提供了多种遍历方法,以下是常用的遍历方法:
public void forEach(Consumer super E> action) {
Objects.requireNonNull(action);
for (int i = 0; i < size; i++) {
E e = elementData[i];
action.accept(e);
}
}
public E get(int index) {
if (index >= size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return (E) elementData[index];
}
public Iterator
iterator() { return new Itr();
}
private class Itr implements Iterator
{ private int cursor; // index of next element to return
private int lastRet = -1; // index of last element returned; -1 if no such
private int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
// 省略其他方法...
}
八、ArrayList的线程稳固性
ArrayList是非线程稳固的,如果多个线程同时访问ArrayList,并且至少有一个线程在结构上修改了列表,这就必须外部同步。以下是一个使用同步代码块来保证线程稳固的示例:
List
list = new ArrayList<>(); synchronized(list) {
list.add("Element1");
list.add("Element2");
// 其他操作...
}
此外,可以使用Collections工具类中的synchronizedList方法来包装ArrayList,使其变为线程稳固的:
List
synchronizedList = Collections.synchronizedList(new ArrayList<>()); synchronizedList.add("Element1");
synchronizedList.add("Element2");
// 其他操作...
九、总结
本文详细分析了ArrayList的源码,包括构造方法、核心成员变量、扩容机制、添加和删除元素方法、遍历方法以及线程稳固性。掌握这些核心知识点,能够帮助开发者更好地领会和使用ArrayList,以及在面对性能问题时能够对其进行优化。