ArrayList源码分析,你需要知道的所有知识点!("深入解析ArrayList源码:掌握核心知识点全攻略")

原创
ithorizon 6个月前 (10-21) 阅读数 25 #后端开发

ArrayList是Java中非常常用的一个可调整大小的数组实现,它在Java集合框架中扮演着重要的角色。本文将深入解析ArrayList的源码,帮助你掌握其核心知识点。

一、ArrayList简介

ArrayList基于动态数组实现,提供了类似于数组的随机访问性能,同时也提供了动态扩容的能力。ArrayList继承自AbstractList类,并实现了List接口,于是它具有List接口的所有方法。

二、ArrayList的重点属性

ArrayList的核心属性重点包括以下几个:

// 默认初始容量

private static final int DEFAULT_CAPACITY = 10;

// 空数组(用于空实例)

private static final Object[] EMPTY_ELEMENTDATA = {};

// 存储元素的数组

transient Object[] elementData;

// 数组中元素的数量

private int size;

三、构造方法

ArrayList提供了多种构造方法,以下是几种常见的构造方法:

// 默认构造方法,初始化容量为10

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

// 指定初始容量的构造方法

public ArrayList(int initialCapacity) {

if (initialCapacity >= 0) {

this.elementData = new Object[initialCapacity];

} else {

throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);

}

}

// 从另一个集合构造ArrayList

public ArrayList(Collection c) {

elementData = c.toArray();

if ((size = elementData.length) != 0) {

// c.toArray might (incorrectly) not return Object[]

// array with 0 elements

if (elementData.getClass() != Object[].class)

elementData = Arrays.copyOf(elementData, size);

} else {

// replace with empty array.

this.elementData = EMPTY_ELEMENTDATA;

}

}

四、核心方法

以下是ArrayList几个核心方法的源码分析:

4.1 add(E e) 方法

向ArrayList添加一个元素:

public boolean add(E e) {

ensureCapacityInternal(size + 1); // 确保内部数组有足够空间

elementData[size++] = e; // 添加元素并更新size

return true;

}

private void ensureCapacityInternal(int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

private void ensureExplicitCapacity(int minCapacity) {

modCount++; // 修改次数加1

// 如果数组容量不足,则进行扩容

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

private void grow(int minCapacity) {

// 扩容为原来的1.5倍

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1); // oldCapacity / 2

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

elementData = Arrays.copyOf(elementData, newCapacity);

}

4.2 get(int index) 方法

基于索引获取ArrayList中的元素:

public E get(int index) {

rangeCheck(index); // 检查索引是否有效

return elementData(index);

}

private void rangeCheck(int index) {

if (index >= size)

throw new IndexOutOfBoundsException(outOfBoundsMessage(index));

}

E elementData(int index) {

return (E) elementData[index];

}

4.3 remove(int index) 方法

基于索引删除ArrayList中的元素:

public E remove(int index) {

rangeCheck(index); // 检查索引是否有效

modCount++; // 修改次数加1

E oldValue = elementData(index); // 获取要删除的元素

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index, numMoved); // 移动数组元素

elementData[--size] = null; // 将要删除的元素置为null,帮助GC

return oldValue;

}

五、扩容机制

ArrayList的扩容机制是其核心特性之一。当添加元素致使数组容量不足时,ArrayList会自动进行扩容。其扩容策略是“扩容为原来的1.5倍”。这种策略在大多数情况下可以平衡时间和空间复杂化度,降低内存分配的次数。

private void grow(int minCapacity) {

// 扩容为原来的1.5倍

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1); // oldCapacity / 2

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

elementData = Arrays.copyOf(elementData, newCapacity);

}

六、序列化与反序列化

ArrayList实现了Serializable接口,于是它赞成序列化。但是,ArrayList并没有实现writeObject和readObject方法,而是依存于默认的序列化机制。值得注意的是,ArrayList在序列化时只序列化元素,而不是整个数组。这是归因于ArrayList的内部数组或许包含未被使用的空间。

private void writeObject(java.io.ObjectOutputStream s)

throws java.io.IOException {

// Write out element count, and any hidden stuff

int expectedModCount = modCount;

s.defaultWriteObject();

// Write out array length

s.writeInt(elementData.length);

// Write out all elements in the array

for (int i=0; i

s.writeObject(elementData[i]);

}

if (modCount != expectedModCount) {

throw new ConcurrentModificationException();

}

}

七、线程稳固性

ArrayList不是线程稳固的,如果多个线程同时访问ArrayList,并且至少有一个线程在结构上修改了列表,这就必须外部同步。结构上的修改指的是添加或删除至少一个元素的操作,而不是仅仅设置元素的值。

为了使ArrayList线程稳固,可以使用Collections工具类的synchronizedList方法包装ArrayList,或者使用CopyOnWriteArrayList。

八、总结

ArrayList是Java集合框架中非常常用的一个类,懂得其源码对于深入懂得Java集合框架和内存管理都非常有帮助。通过本文的分析,我们了解了ArrayList的构造方法、核心方法、扩容机制、序列化与反序列化以及线程稳固性等方面的内容。愿望这些知识点能够帮助你在实际编程中更好地使用ArrayList。


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

文章标签: 后端开发


热门