⚙️ 一、核心概念
- Native方法
System.arraycopy()
是JVM提供的本地方法(native
),通过JNI调用操作系统底层内存操作(如C的memmove
),实现高效数据块复制。 - 浅拷贝(Shallow Copy)
- 基本类型数组(
int[]
,double[]
):复制元素值(深拷贝效果) - 对象数组(
Object[]
):复制引用地址(共享对象实例)
- 基本类型数组(
- 线程安全与原子性
底层使用conjoint_memory_atomic
确保多线程环境下内存复制的原子性。
📝 二、操作步骤详解
方法签名
public static native void arraycopy(
Object src, // 源数组
int srcPos, // 源数组起始索引
Object dest, // 目标数组
int destPos, // 目标数组起始索引
int length // 复制元素数量
);
步骤示例
基础复制(一维数组)
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]
自复制(数组内移动元素)
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]
对象数组复制
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(引用相同)
❌ 三、常见错误分析
数组越界
若srcPos + length > src.length
或destPos + length > dest.length
,抛出IndexOutOfBoundsException
。int[] src = new int[5]; int[] dest = new int[3]; System.arraycopy(src, 0, dest, 0, 5); // 抛出异常
类型不兼容
源数组与目标数组类型不匹配时(如String[]
复制到Integer[]
),抛出ArrayStoreException
。浅拷贝陷阱
修改对象数组副本中的对象属性,会直接影响原数组(因引用相同):copy[0].setName("Charlie"); System.out.println(users[0].getName()); // 输出 "Charlie"
⚠️ 四、关键注意事项
参数校验
JVM在本地代码中严格检查参数:- 非空校验:
src
或dest
为null
→NullPointerException
- 负索引校验:
srcPos <0
或length <0
→IndexOutOfBoundsException
。
- 非空校验:
自复制处理
源与目标为同一数组时,底层自动处理内存重叠(类似C的memmove
),无需额外检查。二维数组特殊性
二维数组本质是“数组的数组”,复制第一维仅复制引用(共享子数组):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]
🛠️ 五、高效使用技巧
批量删除数组元素
利用自复制实现高效删除(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]
动态数组合并
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);
避免中间复制
大数组操作时,直接复用arraycopy
而非Arrays.copyOf
(后者内部调用前者但需创建新数组)。
🚀 六、最佳实践与性能优化
性能对比基准 | 复制方法 | 复制10,000个元素耗时 | 适用场景 | |----------------------|----------------------|-----------------------| |
System.arraycopy()
| ~0.2ms | 大数据量、高性能需求 | |Arrays.copyOf()
| ~0.3ms | 简洁代码+创建新数组 | |for
循环 | ~1.5ms | 小数据量或复杂处理 | |clone()
| ~0.4ms | 简单全量复制内存敏感场景优化
- 复用目标数组减少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); }
安全深拷贝方案
对象数组需深拷贝时,结合序列化或手动复制:// 使用流深拷贝(需实现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优化) |
浅拷贝风险 | 对象数组复制后修改需谨慎,必要时深拷贝 |
错误预防 | 严格校验srcPos 、destPos 和length 的合法性 |
性能临界点 | 数据量>100时,arraycopy 显著优于循环复制 |
黄金准则:
- ✅ 大数据操作必选:超过1KB数据复制时无条件使用
arraycopy
;- ✅ 对象数组警惕引用:修改副本前评估对原数据的影响;
- ✅ 复用优于新建:高频操作中复用目标数组降低GC开销。
通过深入理解内存复制机制与严格遵循最佳实践,可显著提升Java应用的数组处理性能。