有兩種方式:
1). 實現 Cloneable 接口並重寫 Object 類中的 clone()方法;
2). 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真
正的深度克隆,代碼如下。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) throws
Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new
ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 說明:調用 ByteArrayInputStream 或 ByteArrayOutputStream
對象的 close 方法沒有任何意義
// 這兩個基於內存的流只要垃圾回收器清理對象就能夠釋放資源,這
一點不同於對外部資源(如文件流)的釋放
}
}
下面是測試代碼:
import java.io.Serializable;
/**
* 人類
* @author 駱昊
*
*/
class Person implements Serializable {
private static final long serialVersionUID = -9102017020286042305L;
private String name;
// 姓名
private int age;
// 年齡
private Car car;
// 座駕
public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
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 Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" +
car + "]";
}
}
/**
* 小汽車類
* @author 駱昊
*
*/
class Car implements Serializable {
private static final long serialVersionUID = -5713945027627603702L;
private String brand;
// 品牌
private int maxSpeed;
// 最高時速
public Car(String brand, int maxSpeed) {this.brand = brand;
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed +
"]";
}
}
class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("Hao LUO", 33, new Car("Benz",
300));
Person p2 = MyUtil.clone(p1);
// 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的 Person 對象 p2 關聯的汽車對象的品牌屬性
// 原來的 Person 對象 p1 關聯的汽車不會受到任何影響
// 因為在克隆 Person 對象時其關聯的汽車對象也被克隆了
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:基於序列化和反序列化實現的克隆不僅僅是深度克隆,更重要的是通過泛
型限定,可以檢查出要克隆的對象是否支持序列化,這項檢查是編譯器完成的,
不是在運行時拋出異常,這種是方案明顯優於使用 Object 類的 clone 方法克隆對
象。讓問題在編譯的時候暴露出來總是好過把問題留到運行時。