Java 数组 clone() 详解:深入示例与最佳实践
发布: (2025年12月14日 GMT+8 21:49)
5 min read
原文: Dev.to
Source: Dev.to
什么是数组的 clone() 方法?
首先要记住的一点:对数组而言,clone() 执行的是 浅拷贝。
浅拷贝 vs. 深拷贝:核心概念
- 浅拷贝 – 创建一个新的数组对象,但其元素仍是指向原数组中相同对象的引用。通过一个数组修改可变对象时,另一个数组也会看到变化。
- 深拷贝 – 完全独立地复制原数组 以及 其中的每个对象。对一个的修改不会影响另一个。
对于基本类型数组(int[]、char[] 等),这个区别并不重要,因为数组存储的是实际值。此时 clone() 实际上会得到一个独立的副本。
对于对象数组(String[]、Employee[] 等),数组存储的是引用,所以浅拷贝只会复制这些引用。
代码示例:动手实践
示例 1 – 基本类型数组
import java.util.Arrays;
public class CloneDemo {
public static void main(String[] args) {
int[] originalScores = {95, 87, 92, 64};
int[] clonedScores = originalScores.clone();
System.out.println("Original Array: " + Arrays.toString(originalScores));
System.out.println("Cloned Array: " + Arrays.toString(clonedScores));
// Change the cloned array
clonedScores[0] = 100;
System.out.println("\nAfter modifying cloned array:");
System.out.println("Original Array: " + Arrays.toString(originalScores)); // Still 95
System.out.println("Cloned Array: " + Arrays.toString(clonedScores)); // Now 100
}
}
输出
Original Array: [95, 87, 92, 64]
Cloned Array: [95, 87, 92, 64]
After modifying cloned array:
Original Array: [95, 87, 92, 64]
Cloned Array: [100, 87, 92, 64]
示例 2 – 陷阱!(对象数组)
class Player {
String name;
int level;
Player(String name, int level) {
this.name = name;
this.level = level;
}
}
public class CloneGotcha {
public static void main(String[] args) {
Player[] originalTeam = {
new Player("Alex", 10),
new Player("Sam", 15)
};
Player[] clonedTeam = originalTeam.clone();
System.out.println("Before change:");
System.out.println("Original[0]: " + originalTeam[0].level); // 10
System.out.println("Cloned[0]: " + clonedTeam[0].level); // 10
// Modify the object referenced by the cloned array
clonedTeam[0].level = 99;
System.out.println("\nAfter changing clonedTeam[0].level to 99:");
System.out.println("Original[0]: " + originalTeam[0].level); // Oops! 99!
System.out.println("Cloned[0]: " + clonedTeam[0].level); // 99
}
}
输出
Before change:
Original[0]: 10
Cloned[0]: 10
After changing clonedTeam[0].level to 99:
Original[0]: 99
Cloned[0]: 99
实际场景:clone() 的适用之处
在 Getter 中进行防御性拷贝
public class Configuration {
private String[] settings;
public String[] getSettings() {
return settings.clone(); // 调用者无法修改内部数组
}
}
作为深拷贝的构建块
clone() 可以作为更复杂深拷贝流程的第一步,随后手动拷贝数组中可变对象。
最佳实践与常见坑
- 假设对象数组是浅拷贝。 如果数组中保存的是可变对象,仅使用
clone()往往不够。 - 需要独立对象时手动深拷贝。例如对
Player数组的深拷贝:
Player[] deepCopyTeam = new Player[originalTeam.length];
for (int i = 0; i (original)` or `list.toArray()` for copying.
-
问:什么时候绝对不该使用
clone()?
答: 当你需要对包含可变对象的数组进行深拷贝,或希望代码意图更明确时;此时Arrays.copyOf、System.arraycopy或手动循环更安全。 -
问:性能如何?
答:clone()是原生的数组拷贝,对浅拷贝来说通常非常快。深拷贝需要额外的工作,速度会随复制的数据量线性下降。
结论:是否应该使用它?
- 使用
clone():适用于基本类型数组、不可变对象数组(String、Integer等),或任何浅拷贝已满足需求的场景。 - 避免
clone():当你需要对可变对象进行独立拷贝时。 - 考虑替代方案:如
Arrays.copyOf、System.arraycopy或显式循环,以获得更清晰的意图和对深拷贝语义的更好控制。
了解 clone() 的工作方式及其局限性,对编写正确且高效的 Java 代码至关重要。