一、方法定义
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.length 或 destPos + length > dest.length |
任一数组为 null | NullPointerException |
传入 null 数组 |
非数组对象 | ArrayStoreException 或 IllegalArgumentException |
传入非数组的 Object |
示例错误:
int[] a = {1, 2};
String[] b = {"x"};
// System.arraycopy(a, 0, b, 0, 1); // ❌ ArrayStoreException
七、注意事项
浅拷贝:对于对象数组,只复制引用,原对象仍共享。
Person[] src = {new Person("Alice")}; Person[] dest = new Person[1]; System.arraycopy(src, 0, dest, 0, 1); dest[0].setName("Bob"); // src[0] 也会被修改!
性能极高:底层为 native 实现,通常比
for
循环快 3~10 倍。不自动扩容:目标数组必须预先分配足够空间。
支持重叠复制:源和目标区域可以重叠,JVM 会正确处理(通常从前向后或从后向前复制)。
线程安全:方法本身线程安全,但数组内容需外部同步。
八、性能分析与优化
方法 | 性能对比 | 说明 |
---|---|---|
System.arraycopy() |
⭐⭐⭐⭐⭐ | 最快,JVM 优化,推荐 |
Arrays.copyOf() |
⭐⭐⭐⭐ | 内部调用 arraycopy ,但会创建新数组 |
clone() |
⭐⭐⭐⭐ | 数组克隆效率高,但只能全量复制 |
for 循环 |
⭐⭐ | 明显慢于 native 方法 |
Stream / Collections |
⭐ | 不适合数组复制,性能差 |
性能测试建议:
- 对于大数组(>1000 元素),
arraycopy
优势明显。 - 小数组(<50)差异不大,但
arraycopy
仍更快。
九、最佳实践
✅ 推荐做法:
- 用于大数组复制、扩容、移动等操作。
- 在集合类(如
ArrayList
、Vector
)内部实现中广泛使用。 - 优先于手动
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 高手必须掌握的底层工具。