⚙️ 一、核心概念

  1. Native方法
    System.arraycopy() 是JVM提供的本地方法native),通过JNI调用操作系统底层内存操作(如C的memmove),实现高效数据块复制。
  2. 浅拷贝(Shallow Copy)
    • 基本类型数组int[], double[]):复制元素值(深拷贝效果)
    • 对象数组Object[]):复制引用地址(共享对象实例)
  3. 线程安全与原子性
    底层使用conjoint_memory_atomic确保多线程环境下内存复制的原子性。

📝 二、操作步骤详解

方法签名

public static native void arraycopy(
    Object src,  // 源数组
    int srcPos,   // 源数组起始索引
    Object dest, // 目标数组
    int destPos,  // 目标数组起始索引
    int length    // 复制元素数量
);

步骤示例

  1. 基础复制(一维数组)

    int[] src = {1, 2, 3, 4, 5};
    int[] dest = new int[5];
    System.arraycopy(src, 0, dest, 0, 5); // dest: [1, 2, 3, 4, 5]
    
  2. 自复制(数组内移动元素)

    int[] arr = {0, 1, 2, 3, 4, 5};
    // 将索引0~2的元素复制到索引3开始的位置
    System.arraycopy(arr, 0, arr, 3, 3); // arr: [0, 1, 2, 0, 1, 2]
    
  3. 对象数组复制

    User[] users = {new User("Alice"), new User("Bob")};
    User[] copy = new User[2];
    System.arraycopy(users, 0, copy, 0, 2);
    System.out.println(users[0] == copy[0]); // true(引用相同)
    

❌ 三、常见错误分析

  1. 数组越界
    srcPos + length > src.lengthdestPos + length > dest.length,抛出IndexOutOfBoundsException

    int[] src = new int[5];
    int[] dest = new int[3];
    System.arraycopy(src, 0, dest, 0, 5); // 抛出异常
    
  2. 类型不兼容
    源数组与目标数组类型不匹配时(如String[]复制到Integer[]),抛出ArrayStoreException

  3. 浅拷贝陷阱
    修改对象数组副本中的对象属性,会直接影响原数组(因引用相同):

    copy[0].setName("Charlie");
    System.out.println(users[0].getName()); // 输出 "Charlie"
    

⚠️ 四、关键注意事项

  1. 参数校验
    JVM在本地代码中严格检查参数:

    • 非空校验:srcdestnullNullPointerException
    • 负索引校验:srcPos <0length <0IndexOutOfBoundsException
  2. 自复制处理
    源与目标为同一数组时,底层自动处理内存重叠(类似C的memmove),无需额外检查。

  3. 二维数组特殊性
    二维数组本质是“数组的数组”,复制第一维仅复制引用(共享子数组):

    int[][] matrix = {{1,2}, {3,4}};
    int[][] copy = new int[2][];
    System.arraycopy(matrix, 0, copy, 0, 2);
    copy[0][0] = 99;  // 修改会影响原数组matrix[0][0]
    

🛠️ 五、高效使用技巧

  1. 批量删除数组元素
    利用自复制实现高效删除(ArrayList的remove()原理):

    int[] arr = {10, 20, 30, 40, 50};
    int indexToRemove = 1; // 删除20
    System.arraycopy(arr, indexToRemove+1, arr, indexToRemove, arr.length-indexToRemove-1);
    arr[arr.length-1] = 0; // 结果: [10, 30, 40, 50, 0]
    
  2. 动态数组合并

    int[] part1 = {1, 2, 3};
    int[] part2 = {4, 5};
    int[] merged = new int[part1.length + part2.length];
    System.arraycopy(part1, 0, merged, 0, part1.length);
    System.arraycopy(part2, 0, merged, part1.length, part2.length);
    
  3. 避免中间复制
    大数组操作时,直接复用arraycopy而非Arrays.copyOf(后者内部调用前者但需创建新数组)。


🚀 六、最佳实践与性能优化

  1. 性能对比基准 | 复制方法 | 复制10,000个元素耗时 | 适用场景 | |----------------------|----------------------|-----------------------| | System.arraycopy() | ~0.2ms | 大数据量、高性能需求 | | Arrays.copyOf() | ~0.3ms | 简洁代码+创建新数组 | | for循环 | ~1.5ms | 小数据量或复杂处理 | | clone() | ~0.4ms | 简单全量复制

  2. 内存敏感场景优化

    • 复用目标数组减少GC压力。
    • 超大数组分块复制(避免长时间阻塞):
      final int BLOCK = 1024;
      for (int i=0; i<src.length; i+=BLOCK) {
          int len = Math.min(BLOCK, src.length - i);
          System.arraycopy(src, i, dest, i, len);
      }
      
  3. 安全深拷贝方案
    对象数组需深拷贝时,结合序列化或手动复制:

    // 使用流深拷贝(需实现Serializable)
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    new ObjectOutputStream(bos).writeObject(srcArray);
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
    User[] deepCopy = (User[]) new ObjectInputStream(bis).readObject();
    

💎 七、总结

关键点 实践建议
底层机制 优先使用arraycopy处理大数据量复制(JNI优化)
浅拷贝风险 对象数组复制后修改需谨慎,必要时深拷贝
错误预防 严格校验srcPosdestPoslength的合法性
性能临界点 数据量>100时,arraycopy显著优于循环复制

黄金准则

  • 大数据操作必选:超过1KB数据复制时无条件使用arraycopy
  • 对象数组警惕引用:修改副本前评估对原数据的影响;
  • 复用优于新建:高频操作中复用目标数组降低GC开销。

通过深入理解内存复制机制与严格遵循最佳实践,可显著提升Java应用的数组处理性能。