Java中的两种克隆方式
Java支持两种克隆方式:
- 浅拷贝(Shallow Copy):只复制对象本身,不复制对象内部引用的其他对象。
- 深拷贝(Deep Copy):不仅复制对象本身,还递归复制所有引用的对象。
实现浅拷贝
要实现浅拷贝,你的类需要实现Cloneable接口并重写clone()方法。
class Person implements Cloneable { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // Getter 和 Setter 方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } // 使用示例 public class Main { public static void main(String[] args) throws CloneNotSupportedException { Person original = new Person("张三", 25); Person cloned = (Person) original.clone(); System.out.println("原始对象: " + original.getName()); System.out.println("克隆对象: " + cloned.getName()); } }
上面的例子展示了基本类型的浅拷贝。但如果对象包含引用类型(如数组、其他对象),浅拷贝就可能出问题。
浅拷贝的问题
假设Person类还有一个Address对象:
class Address { private String city; public Address(String city) { this.city = city; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } } class Person implements Cloneable { private String name; private Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 这是浅拷贝! } // Getter 和 Setter public Address getAddress() { return address; } } // 测试 public class Main { public static void main(String[] args) throws CloneNotSupportedException { Address addr = new Address("北京"); Person original = new Person("李四", addr); Person cloned = (Person) original.clone(); // 修改克隆对象的地址 cloned.getAddress().setCity("上海"); System.out.println("原始对象城市: " + original.getAddress().getCity()); // 输出:上海! } }
可以看到,修改克隆对象的地址也影响了原始对象,因为它们共享同一个Address实例。这就是浅拷贝的局限性。
实现深拷贝
为了解决这个问题,我们需要实现Java深拷贝。有几种方法:
方法一:手动克隆每个引用对象
@Override protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); // 手动克隆引用对象 cloned.address = (Address) this.address.clone(); return cloned; }
注意:Address类也需要实现Cloneable并重写clone()方法。
方法二:使用序列化(推荐用于复杂对象)
import java.io.*; public static T deepCopy(T object) throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(object); out.flush(); out.close(); ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(bos.toByteArray()) ); @SuppressWarnings("unchecked") T copy = (T) in.readObject(); in.close(); return copy; }
这种方法要求所有相关类都实现Serializable接口。
总结
- Java对象克隆是创建对象副本的重要技术。
- Java浅拷贝速度快但可能引发共享引用问题。
- Java深拷贝更安全但实现更复杂。
- 正确使用clone()方法需要理解其工作原理和限制。
希望这篇教程能帮助你掌握Java clone方法的使用。动手实践是学习的最佳方式,不妨自己写几个例子试试看!