ArrayList 是 Java 集合框架(Java Collections Framework)中的一个重要类,
它实现了 List 接口,是基于数组实现的动态数组。
由于其内部采用数组来存储元素,因此它可以提供随机访问(即直接通过索引访问元素)的能力,
同时支持自动扩容以容纳更多的元素。下面我将简要地解析 ArrayList 的关键源码部分。
1. 成员变量
ArrayList 的主要成员变量包括:
Object[] elementData:用于存储元素的数组。private int size:当前数组中存储的元素数量。private static final int DEFAULT_CAPACITY = 10:默认的初始容量。private static final Object[] EMPTY_ELEMENTDATA = {}:一个空数组实例,用于空实例的共享。private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8:数组的最大容量。
2. 构造函数
ArrayList 提供了几个构造函数来创建实例:
- 无参构造函数:创建一个空的
ArrayList,其初始容量为 10。 - 带有初始容量的构造函数:创建一个空的
ArrayList,但你可以指定初始容量。 - 带有
Collection的构造函数:通过传入一个Collection来创建一个包含Collection所有元素的ArrayList。
3. 动态扩容
当向 ArrayList 添加元素时,如果当前数组大小不足以容纳新元素,ArrayList 会自动扩容。
扩容通常是将数组大小增加到原来的 1.5 倍(确切的增长因子可能会根据 JVM 的实现而有所不同),
但也会受到 MAX_ARRAY_SIZE 的限制。
4. 关键方法
add(E e):向列表的末尾添加指定的元素。remove(int index):移除列表中指定位置的元素。get(int index):返回列表中指定位置的元素。size():返回列表中的元素数量。ensureCapacity(int minCapacity):确保列表的容量至少为指定的最小值。trimToSize():将数组的容量调整为列表的当前大小。
5. 示例代码片段
以下是一个 add 方法的简化示例:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 扩容检查
elementData[size++] = e; // 将元素添加到数组末尾,并更新 size
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
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);
// copy 数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
以上只是 ArrayList 源码的一部分解析,但它涵盖了 ArrayList 的基本工作原理和关键特性。
ArrayList 是 Java 集合框架中非常基础且常用的类,
理解其实现原理对于深入理解 Java 集合框架非常有帮助。
ArrayList和List在Java集合框架中扮演着不同的角色,它们的底层实现和原理既有相似之处也存在显著差异。以下是对它们底层实现和原理的异同点的详细分析:
共同点
-
集合框架的一部分:
- ArrayList和List都是Java集合框架(Java Collections Framework)的一部分。List是一个接口,而ArrayList是List接口的一个具体实现类。
-
动态扩展:
- 两者都可以动态地扩展其容量以存储更多的元素。尽管List本身是一个接口,但其实现类(如ArrayList)通常都支持动态扩容。
差异点
-
实现方式:
- ArrayList:基于数组实现,是一个动态数组。当元素被添加到ArrayList时,如果其当前的容量不足以容纳新元素,则ArrayList会自动扩容。扩容通常涉及创建一个新的、更大的数组,并将旧数组的元素复制到新数组中。ArrayList的扩容机制确保了它可以按需增长,但也可能导致一定的性能开销,特别是在添加大量元素时。
- List:作为一个接口,它本身不直接实现任何数据结构。List的底层实现可以因实现类的不同而异。例如,除了ArrayList的数组实现外,还有基于链表实现的LinkedList等。
-
性能特点:
- ArrayList:由于基于数组实现,ArrayList在随机访问(即通过索引访问元素)时具有较高的效率(时间复杂度为O(1))。然而,在插入和删除元素时,可能需要移动数组中的其他元素以腾出空间或填补空缺,这可能导致较高的时间复杂度(最坏情况下为O(n))。
- List:由于List是一个接口,其性能特点取决于具体的实现类。以LinkedList为例,它在插入和删除元素时具有较高的效率(时间复杂度为O(1)或O(n),取决于操作的位置),但在随机访问时效率较低(时间复杂度为O(n))。
-
线程安全性:
- ArrayList:是非线程安全的。在多线程环境下,如果不进行同步处理,可能会遇到线程安全问题。
- List:作为一个接口,其线程安全性也取决于具体的实现类。Java提供了线程安全的List实现,如CopyOnWriteArrayList,但这不是List接口本身的固有属性。
-
功能差异:
- ArrayList:提供了基于数组的一系列操作方法,如
add(E e)、remove(int index)、get(int index)等。 - List:作为接口,它定义了操作有序集合的一系列方法,如
boolean add(E e)、E remove(int index)、E get(int index)等。这些方法的具体实现由实现类提供。
- ArrayList:提供了基于数组的一系列操作方法,如
综上所述,ArrayList和List在底层实现和原理上存在显著差异。ArrayList基于数组实现,具有动态扩容、随机访问效率高等特点;而List作为一个接口,其底层实现可以多样,性能特点也取决于具体的实现类。在实际应用中,应根据具体需求选择合适的实现类。