### 7. `ArrayList` 的其他方法
#### 7.1 `size()` 方法
返回 `ArrayList` 中元素的数量:
```java
public int size() {
return size;
}
```
#### 7.2 `isEmpty()` 方法
判断 `ArrayList` 是否为空:
```java
public boolean isEmpty() {
return size == 0;
}
```
#### 7.3 `clear()` 方法
清空 `ArrayList` 中的所有元素:
```java
public void clear() {
modCount++;
// clear to let GC do its work
```java
for (int i = 0; i < size; i++) {
elementData[i] = null;
}
size = 0;
}
```
`clear()` 方法通过将 `elementData` 数组中的每个元素设置为 `null` 来清空 `ArrayList`,然后将 `size` 设为 0。这样可以确保垃圾回收器能够回收这些对象。
### 8. `ArrayList` 的序列化与克隆
#### 8.1 序列化
`ArrayList` 实现了 `Serializable` 接口,允许其对象被序列化。`writeObject` 和 `readObject` 方法用于自定义序列化逻辑。
```java
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 size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new java.io.ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
```
- `writeObject`:写入 `ArrayList` 的元素数量和每个元素。
- `readObject`:读取 `ArrayList` 的元素数量,并根据数量分配数组,然后逐个读取元素。
#### 8.2 克隆
`ArrayList` 实现了 `Cloneable` 接口,提供了 `clone` 方法用于深度克隆。
```java
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
```
`clone` 方法通过 `super.clone` 创建一个新的 `ArrayList` 实例,并复制 `elementData` 数组。这样可以确保新实例是原实例的一个深拷贝。
### 9. `ArrayList` 的性能分析
#### 9.1 时间复杂度
- **添加元素**:在数组末尾添加元素的平均时间复杂度为 O(1)。在最坏情况下,当数组需要扩容时,时间复杂度为 O(n)。
- **插入元素**:在数组中间插入元素的时间复杂度为 O(n),因为需要移动后续元素。
- **删除元素**:在数组中间删除元素的时间复杂度为 O(n),因为需要移动后续元素。
- **随机访问**:`ArrayList` 支持通过索引随机访问元素,时间复杂度为 O(1)。
#### 9.2 空间复杂度
`ArrayList` 使用一个数组来存储元素,其空间复杂度主要取决于数组的容量。为了减少扩容操作带来的开销,`ArrayList` 在扩容时会将容量增加到当前容量的 1.5 倍。这种策略虽然会导致在某些情况下多余的空间,但可以有效减少扩容次数,提高整体性能。
### 10. `ArrayList` 的缺点和使用场景
#### 10.1 缺点
- **插入和删除操作效率低**:由于插入和删除操作需要移动大量元素,因此在频繁插入和删除元素的场景下,`ArrayList` 的性能较低。
- **占用额外空间**:为了减少扩容次数,`ArrayList` 会预留多余的空间,这可能导致内存浪费,尤其是在元素数量不确定的情况下。
#### 10.2 使用场景
- **随机访问场景**:`ArrayList` 适用于需要频繁进行随机访问的场景,如读取元素的操作。
- **元素数量相对稳定**:当元素数量相对稳定或变化不大时,`ArrayList` 的性能较好。
### 11. `ArrayList` 的替代方案
在某些特定场景下,其他集合类可能比 `ArrayList` 更合适。例如:
- **`LinkedList`**:`LinkedList` 基于双向链表实现,适用于频繁插入和删除操作的场景。与 `ArrayList` 不同,`LinkedList` 插入和删除元素的时间复杂度为 O(1),但随机访问元素的时间复杂度为 O(n)。
- **`Vector`**:`Vector` 与 `ArrayList` 类似,但 `Vector` 是线程安全的,每个方法都用 `synchronized` 修饰,因此在多线程环境下使用 `Vector` 可以确保线程安全,但性能较低。
- **`CopyOnWriteArrayList`**:`CopyOnWriteArrayList` 是线程安全的变体,适用于读多写少的并发场景。
### 12. 总结
`ArrayList` 是 Java 集合框架中的一个重要类,提供了基于数组的动态集合实现。通过详细分析 `ArrayList` 的源码,可以更好地理解其内部机制和工作原理。`ArrayList` 适用于频繁进行随机访问和遍历操作的场景,但在插入和删除操作频繁的场景下,可能需要考虑其他集合类。
通过深入了解 `ArrayList` 的数据结构、构造方法、核心操作、自动扩容机制等,可以更有效地使用 `ArrayList` 并优化程序性能。同时,了解其局限性和替代方案,有助于在不同应用场景中选择最合适的集合类。