一、方法定义

public static void arraycopy(
    Object src,      // 源数组
    int srcPos,      // 源数组中的起始位置
    Object dest,     // 目标数组
    int destPos,     // 目标数组中的起始位置
    int length       // 要复制的元素个数
)
  • 所属类java.lang.System
  • 访问修饰符public static
  • 返回类型void
  • 是否抛出异常:是(见下文)
  • 底层实现:本地方法(Native),通常由 JVM 用 C/C++ 实现,性能极高

✅ 适用于所有数组类型(基本类型和引用类型)


二、功能说明

System.arraycopy() 用于 高效地将一个数组的一部分复制到另一个数组中,支持:

  • 基本类型数组:int[], char[], byte[]
  • 引用类型数组:String[], Object[], 自定义类数组等
  • 同一数组内复制(可用于数组移动、删除元素等)
  • 跨数组复制(不同数组之间)

⚠️ 是浅拷贝(Shallow Copy),对于引用类型,只复制引用,不复制对象本身。


三、参数详解

参数 类型 说明
src Object 源数组(必须是数组类型)
srcPos int 源数组中开始复制的索引(从0开始)
dest Object 目标数组
destPos int 目标数组中开始放置的索引
length int 要复制的元素个数

所有索引必须在有效范围内,否则抛出异常。


四、示例代码

1. 基本数组复制(int[])

int[] src = {1, 2, 3, 4, 5};
int[] dest = new int[5];

System.arraycopy(src, 0, dest, 0, 3);
// 结果:dest = {1, 2, 3, 0, 0}

2. 字符串数组复制

String[] src = {"A", "B", "C", "D"};
String[] dest = new String[3];

System.arraycopy(src, 1, dest, 0, 3);
// 结果:dest = {"B", "C", "D"}

3. 同一数组内移动元素(删除索引1的元素)

int[] arr = {10, 20, 30, 40, 50};
int indexToRemove = 1;

System.arraycopy(arr, indexToRemove + 1,  // 源:从20后面开始
                 arr, indexToRemove,       // 目标:从20位置开始覆盖
                 5 - indexToRemove - 1);   // 复制3个元素

// 结果:arr = {10, 30, 40, 50, 50} (最后一位可忽略或截断)

4. 扩容数组(模拟 ArrayList 扩容)

int[] oldArray = {1, 2, 3};
int[] newArray = new int[6];

System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
// 结果:newArray = {1, 2, 3, 0, 0, 0}

五、使用技巧

1. 高效扩容与缩容

// 扩容
int[] newArray = new int[oldArray.length * 2];
System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);

// 缩容(复制前 n 个)
int[] smallArray = new int[2];
System.arraycopy(oldArray, 0, smallArray, 0, 2);

2. 数组前移/后移

// 向前移动1位(模拟出队)
System.arraycopy(arr, 1, arr, 0, arr.length - 1);
arr[arr.length - 1] = 0; // 清理最后一位

3. 安全复制(带边界检查)

public static void safeArrayCopy(int[] src, int[] dest) {
    int len = Math.min(src.length, dest.length);
    System.arraycopy(src, 0, dest, 0, len);
}

六、常见错误与异常

错误 异常 说明
数组类型不匹配 ArrayStoreException 如将 String[] 复制到 int[]
索引越界 IndexOutOfBoundsException srcPos + length > src.lengthdestPos + length > dest.length
任一数组为 null NullPointerException 传入 null 数组
非数组对象 ArrayStoreExceptionIllegalArgumentException 传入非数组的 Object

示例错误:

int[] a = {1, 2};
String[] b = {"x"};
// System.arraycopy(a, 0, b, 0, 1); // ❌ ArrayStoreException

七、注意事项

  1. 浅拷贝:对于对象数组,只复制引用,原对象仍共享。

    Person[] src = {new Person("Alice")};
    Person[] dest = new Person[1];
    System.arraycopy(src, 0, dest, 0, 1);
    dest[0].setName("Bob"); // src[0] 也会被修改!
    
  2. 性能极高:底层为 native 实现,通常比 for 循环快 3~10 倍。

  3. 不自动扩容:目标数组必须预先分配足够空间。

  4. 支持重叠复制:源和目标区域可以重叠,JVM 会正确处理(通常从前向后或从后向前复制)。

  5. 线程安全:方法本身线程安全,但数组内容需外部同步。


八、性能分析与优化

方法 性能对比 说明
System.arraycopy() ⭐⭐⭐⭐⭐ 最快,JVM 优化,推荐
Arrays.copyOf() ⭐⭐⭐⭐ 内部调用 arraycopy,但会创建新数组
clone() ⭐⭐⭐⭐ 数组克隆效率高,但只能全量复制
for 循环 ⭐⭐ 明显慢于 native 方法
Stream / Collections 不适合数组复制,性能差

性能测试建议:

  • 对于大数组(>1000 元素),arraycopy 优势明显。
  • 小数组(<50)差异不大,但 arraycopy 仍更快。

九、最佳实践

推荐做法

  • 用于大数组复制、扩容、移动等操作。
  • 在集合类(如 ArrayListVector)内部实现中广泛使用。
  • 优先于手动 for 循环。
  • Arrays.copyOf() 结合使用(后者更简洁但性能略低)。

避免做法

  • 用于小数组且调用频繁的场景(可考虑栈上分配或缓存)。
  • 期望深拷贝对象数组(应使用序列化或手动复制)。
  • 忽略异常处理(生产环境应做边界检查)。

十、替代方案对比

方法 优点 缺点 适用场景
System.arraycopy() 最快、最灵活 需手动创建目标数组 高性能、底层操作
Arrays.copyOf() 简洁、自动创建数组 略慢(封装一层) 通用复制
clone() 简单、天然支持 只能全量复制 全量复制
BufferedReader/流 适合大文件 不适合内存数组 文件处理

示例对比:

// 方式1:arraycopy(最高效)
int[] dest1 = new int[src.length];
System.arraycopy(src, 0, dest1, 0, src.length);

// 方式2:Arrays.copyOf(更简洁)
int[] dest2 = Arrays.copyOf(src, src.length);

// 方式3:clone(仅全量)
int[] dest3 = src.clone();

十一、总结

项目 要点
本质 JVM 本地方法,高效复制数组内容
用途 数组复制、扩容、移动、删除等
性能 ⭐⭐⭐⭐⭐,Java 中最快的数组复制方式
精度 支持所有数组类型(基本 + 引用)
限制 浅拷贝、需预分配目标数组、可能抛异常
推荐替代 Arrays.copyOf()(简洁)、clone()(全量)
关键建议 大数组用 arraycopy,小数组可选 copyOf,避免 for 循环

一句话总结
System.arraycopy() 是 Java 中性能最高的数组复制方法,是 ArrayList 等集合扩容的底层核心,适合高性能场景。虽然使用略繁琐,但其效率无可替代,是 Java 高手必须掌握的底层工具。