广告

手把手教你在Java中创建类数组结构,附带遍历技巧与完整代码实例

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 循环、以及基于索引的遍历。结合 getsizeiterator,你可以自由选择遍历策略。

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);
  }
}
广告

后端开发标签