ArrayList源码分析,你需要知道的所有知识点!("ArrayList源码详解:掌握必备核心知识点!")

原创
ithorizon 7个月前 (10-19) 阅读数 24 #后端开发

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 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 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 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,以及在面对性能问题时能够对其进行优化。


本文由IT视界版权所有,禁止未经同意的情况下转发

文章标签: 后端开发


热门