http://tomsui.blog.hexun.com/4308236_d.html
方法(一) 引用拷貝
Employee original = new Employee ("tomsui",4000);
Employee copy = original ;
original 與copy僅僅是同一對象的不同引用。
?
方法(二) 淺克隆
直接利用Object的clone()方法:
protected Objectclone()?? throws CloneNotSupportedException
Employee copy = (Employee)original.clone();
注意兩點:
1) Object的clone() 是protected. 只能在包內或子類調用.
2) 如果淺克隆的對象中存在對象形式的成員變量:
public class Employee
{
??????? String name;
??????? int salary;
??????? Date birthday;
}
那么:
? Employee copy = (Employee) original.clone();
只是拷貝了original對象中的基本類型和不變量.可變的對象成員變量拷貝得到的仍然是引用.
不變量應該包括(可以參見<java多線程設計模式>Immutable模式中界定的情況):
a. String類對象
b. 被final定義,子對象在生存周期中僅保存一些常量
?
方法(三) 深克隆
例子:
class Employee implements Cloneable
{
??????? private String name;
??????? private double salary;
??????? private Date birthday;
??????? // setter 與 getter
??????? public Object clone()
??????? {
??????????????? try
??????????????? {
??????????????????????? Employee cloned = (Employee ) super.clone();
??????????????????????? cloned.birthday = (Date) birthday.clone();
??????????????? }catch(CloneNotSupportedException e) {
??????????????? return null;
??????????????? }
??????? }
}
?說明:
1)Employee 必須實現 Cloneable接口 (標志接口)
?????標志接口:完全的空接口。這里的作用是告訴JVM,類的設計者理解了cloneable()方法,可以通過isInstanceOf進行運行時檢查。
2)覆寫的clone()方法必須定義為public (原是protected)
3)clone()方法體必須在try-catch {}中,捕獲處理CloneNotSupportedException 。(防止類沒有實現Cloneable接口,正確實現了深克隆的話,這個異常肯定不會拋出)
ps.?? JDK中,StringBuffer沒有覆寫clone()方法,雖然它確實繼承了Object的clone(),但在實際應用中, 因為StringBuffer絕不會有子類,而且是在JDK外使用StringBuffer,所以被protected界定的clone()方法是完全不可見的!
?
方法(四)使用序列化進行克隆
這種方法涉及IO操作,所以相對來講要比方法(三)慢.
import java.io.*;
import java.util.*;
public class SerialCloneTest
{?
?? public static void main(String[] args)
?? {?
????? Employee harry = new Employee("Harry Hacker", 35000,
???????? 1989, 10, 1);
????? // clone harry
????? Employee harry2 = (Employee)harry.clone();
????? // mutate harry
????? harry.raiseSalary(10);
????? // now harry and the clone are different
????? System.out.println(harry);
????? System.out.println(harry2);
?? }
}
/**
?? A class whose clone method uses serialization.
*/
class SerialCloneable implements Cloneable, Serializable
{?
?? public Object clone()
?? {?
????? try
????? {?
???????? // save the object to a byte array
???????? ByteArrayOutputStream bout = new
??????????? ByteArrayOutputStream();
???????? ObjectOutputStream out
??????????? = new ObjectOutputStream(bout);
???????? out.writeObject(this);
???????? out.close();
???????? // read a clone of the object from the byte array
???????? ByteArrayInputStream bin = new
??????????? ByteArrayInputStream(bout.toByteArray());
???????? ObjectInputStream in = new ObjectInputStream(bin);
???????? Object ret = in.readObject();
???????? in.close();
???????? return ret;
????? }?
????? catch (Exception e)
????? {?
???????? return null;
????? }
?? }
}
/**
?? The familiar Employee class, redefined to extend the
?? SerialCloneable class.
*/
class Employee extends SerialCloneable
{?
?? public Employee(String n, double s,
????? int year, int month, int day)
?? {?
????? name = n;
????? salary = s;
????? GregorianCalendar calendar
???????? = new GregorianCalendar(year, month - 1, day);
???????? // GregorianCalendar uses 0 for January
????? hireDay = calendar.getTime();
?? }
?? public String getName()
?? {?
????? return name;
?? }
?? public double getSalary()
?? {?
????? return salary;
?? }
?? public Date getHireDay()
?? {?
????? return hireDay;
?? }
?? public void raiseSalary(double byPercent)
?? {?
????? double raise = salary * byPercent / 100;
????? salary += raise;
?? }
?? public String toString()
?? {?
????? return getClass().getName()
???????? + "[name=" + name
???????? + ",salary=" + salary
???????? + ",hireDay=" + hireDay
???????? + "]";
?? }
?? private String name;
?? private double salary;
?? private Date hireDay;
}
?
?方法(五) 其他方法
可以通過java的反射機制定義一個類似于對象序列化的萬能克隆。改進后再貼上來。