1. 需求理解与设计目标
1.1 背景与核心目标
在 Java 开发中,类数组结构指向一个自定义的容器,它具备数组的快速下标访问能力与 动态扩容 的特性。实现该结构的目的是提供一个可重复使用、类型安全 的容器,用于管理同一类型的对象集合。
本文将通过一个名为 ClassArray<T> 的实现来演示要点,核心包括 泛型化、容量管理 与 遍历能力,以便你在实际项目中可以直接引用或改造。
2. 构建基础容器:骨架与容量管理
2.1 字段与初始化
底层存储采用 Object[] data,元素数量由 size 控制。初始容量通常设定为 10,以实现较低的初始内存占用并降低频繁扩容的概率。
通过构造函数完成对 data 的初始化,并严格维护 size 的一致性,从而避免越界访问或残留引用造成的潜在问题。
2.2 动态扩容策略
当新元素加入导致容量不足时,触发 ensureCapacity,通常采用翻倍的扩容策略,例如将容量扩展为当前容量的两倍或至少达到所需容量,以实现低摊销成本的写入操作。
这种扩容策略与 Java 原生集合中的实现方式类似,确保在大多数使用场景下的性能稳健,同时避免频繁的数组复制带来的开销。
3. 核心方法:添加、访问、删除与遍历
3.1 添加与容量检查
向容器中添加元素时,首先进行容量检查;若容量不足,调用 ensureCapacity 将容量扩展到至少 size+1,随后把元素写入 data[size],再将 size 增加。
访问与修改操作需要进行 范围检查,确保下标落在 [0, Size) 的合法区间,以避免 IndexOutOfBoundsException。
3.2 删除、遍历与工具方法
删除通常涉及向前移动后续元素以保持数组的紧凑性,常用 System.arraycopy 来实现快速复制,并在末尾清理引用以帮助垃圾回收。
为实现多种遍历方式,该容器实现了 Iterable<T>,从而支持 增强型 for 循环、以及基于索引的遍历。结合 get、size、iterator,你可以自由选择遍历策略。
4. 遍历技巧与不同遍历方式
4.1 基础遍历:索引与增强型 for
基于下标的遍历允许你控制遍历起点、终点和步长,适用于需要随机访问或修改容器中元素的场景。
增强型 for 循环使用 Iterable 的实现,语义更清晰,代码更简洁。遍历的稳定性需要注意在遍历过程中对容器进行结构性修改的影响。
4.2 迭代器遍历的好处
实现自定义的 Iterator 可在遍历过程中加入额外行为,例如记录访问日志、实现按需跳过元素等,亦能在某些并发场景下提供简单的遍历控制。
通过迭代器,你可以在不暴露内部实现细节的情况下实现高级遍历特性,提升封装性与复用性。
5. 完整代码示例与演示
5.1 完整代码片段(ClassArray 与演示)
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* 手把手实现的一个简单“类数组结构”容器
* 支持泛型、动态扩容、下标访问、删除与遍历
*/
public class ClassArray<T> implements Iterable<T> {
private Object[] data;
private int size;
private static final int DEFAULT_CAPACITY = 10;
public ClassArray() {
this(DEFAULT_CAPACITY);
}
public ClassArray(int initialCapacity) {
if (initialCapacity < 1) {
throw new IllegalArgumentException("Initial capacity must be >= 1");
}
this.data = new Object[initialCapacity];
this.size = 0;
}
// 添加元素并确保容量
public void add(T item) {
ensureCapacity(size + 1);
data[size++] = item;
}
// 获取元素,带边界检查
@SuppressWarnings("unchecked")
public T get(int index) {
rangeCheck(index);
return (T) data[index];
}
// 设置元素
public void set(int index, T item) {
rangeCheck(index);
data[index] = item;
}
public int size() {
return size;
}
// 删除指定下标的元素
public boolean remove(int index) {
rangeCheck(index);
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(data, index + 1, data, index, numMoved);
}
data[--size] = null; // 清理最后一个引用,帮助 GC
return true;
}
// ensureCapacity: 扩容策略
private void ensureCapacity(int minCapacity) {
if (minCapacity > data.length) {
int newCap = Math.max(data.length * 2, minCapacity);
data = Arrays.copyOf(data, newCap);
}
}
// 范围检查
private void rangeCheck(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
// 迭代器实现:支持 foreach
@Override
public Iterator iterator() {
return new Iterator() {
int cursor = 0;
@Override
public boolean hasNext() {
return cursor < size;
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
return (T) data[cursor++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
// 便于调试的输出
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < size; i++) {
if (i > 0) sb.append(", ");
sb.append(data[i]);
}
sb.append("]");
return sb.toString();
}
// 演示用 main:创建、添加、遍历、修改与删除
public static void main(String[] args) {
ClassArray<String> ca = new ClassArray<>();
ca.add("Alpha");
ca.add("Beta");
ca.add("Gamma");
// 基于 Iterable 的遍历
for (String s : ca) {
System.out.println("元素: " + s);
}
// 基于索引的遍历
for (int i = 0; i < ca.size(); i++) {
System.out.println("索引 " + i + " -> " + ca.get(i));
}
// 修改与删除示例
ca.set(1, "Delta");
ca.remove(0);
System.out.println("最终容器: " + ca);
}
} 

