參考copy鏈接:http://blog.csdn.net/bigconvience/article/details/25025561
在看原型模式,發現要用到clone這個方法,以前和朋友聊過,沒怎么看過,剛好要用,就看看了。
源碼解釋:
/** * Creates and returns a copy of this object. The precise meaning * of "copy" may depend on the class of the object. The general * intent is that, for any object {@code x}, the expression: * <blockquote> * <pre> * x.clone() != x</pre></blockquote> * will be true, and that the expression: * <blockquote> * <pre> * x.clone().getClass() == x.getClass()</pre></blockquote> * will be {@code true}, but these are not absolute requirements. * While it is typically the case that: * <blockquote> * <pre> * x.clone().equals(x)</pre></blockquote> * will be {@code true}, this is not an absolute requirement. * <p> * By convention, the returned object should be obtained by calling * {@code super.clone}. If a class and all of its superclasses (except * {@code Object}) obey this convention, it will be the case that * {@code x.clone().getClass() == x.getClass()}. * <p> * By convention, the object returned by this method should be independent * of this object (which is being cloned). To achieve this independence, * it may be necessary to modify one or more fields of the object returned * by {@code super.clone} before returning it. Typically, this means * copying any mutable objects that comprise the internal "deep structure" * of the object being cloned and replacing the references to these * objects with references to the copies. If a class contains only * primitive fields or references to immutable objects, then it is usually * the case that no fields in the object returned by {@code super.clone} * need to be modified. * <p> * The method {@code clone} for class {@code Object} performs a * specific cloning operation. First, if the class of this object does * not implement the interface {@code Cloneable}, then a * {@code CloneNotSupportedException} is thrown. Note that all arrays * are considered to implement the interface {@code Cloneable} and that * the return type of the {@code clone} method of an array type {@code T[]} * is {@code T[]} where T is any reference or primitive type. * Otherwise, this method creates a new instance of the class of this * object and initializes all its fields with exactly the contents of * the corresponding fields of this object, as if by assignment; the * contents of the fields are not themselves cloned. Thus, this method * performs a "shallow copy" of this object, not a "deep copy" operation. * <p> * The class {@code Object} does not itself implement the interface * {@code Cloneable}, so calling the {@code clone} method on an object * whose class is {@code Object} will result in throwing an * exception at run time. * * @return a clone of this instance. * @throws CloneNotSupportedException if the object's class does not * support the {@code Cloneable} interface. Subclasses * that override the {@code clone} method can also * throw this exception to indicate that an instance cannot * be cloned. * @see java.lang.Cloneable */ protected native Object clone() throws CloneNotSupportedException;
一大串英文我看不怎么懂,都是看別人的博客和翻譯文檔的。
中文jdk文檔:
clone protected Object clone() throws CloneNotSupportedException 創建並返回此對象的一個副本。“副本”的准確含義可能依賴於對象的類。這樣做的目的是,對於任何對象 x,表達式: x.clone() != x 為 true,表達式: x.clone().getClass() == x.getClass() 也為 true,但這些並非必須要滿足的要求。一般情況下: x.clone().equals(x) 為 true,但這並非必須要滿足的要求。 按照慣例,返回的對象應該通過調用 super.clone 獲得。如果一個類及其所有的超類(Object 除外)都遵守此約定,則 x.clone().getClass() == x.getClass()。 按照慣例,此方法返回的對象應該獨立於該對象(正被復制的對象)。要獲得此獨立性,在 super.clone 返回對象之前,有必要對該對象的一個或多個字段進行修改。這通常意味着要復制包含正在被復制對象的內部“深層結構”的所有可變對象,並使用對副本的引用替換對這些對象的引用。如果一個類只包含基本字段或對不變對象的引用,那么通常不需要修改 super.clone 返回的對象中的字段。 Object 類的 clone 方法執行特定的復制操作。首先,如果此對象的類不能實現接口 Cloneable,則會拋出 CloneNotSupportedException。注意,所有的數組都被視為實現接口 Cloneable。否則,此方法會創建此對象的類的一個新實例,並像通過分配那樣,嚴格使用此對象相應字段的內容初始化該對象的所有字段;這些字段的內容沒有被自我復制。所以,此方法執行的是該對象的“淺表復制”,而不“深層復制”操作。 Object 類本身不實現接口 Cloneable,所以在類為 Object 的對象上調用 clone 方法將會導致在運行時拋出異常。 返回: 此實例的一個副本。 拋出: CloneNotSupportedException - 如果對象的類不支持 Cloneable 接口,則重寫 clone 方法的子類也會拋出此異常,以指示無法復制某個實例。 另請參見: Cloneable
cloneable接口的文檔:
public interface Cloneable 此類實現了 Cloneable 接口,以指示 Object.clone() 方法可以合法地對該類實例進行按字段復制。 如果在沒有實現 Cloneable 接口的實例上調用 Object 的 clone 方法,則會導致拋出 CloneNotSupportedException 異常。 按照慣例,實現此接口的類應該使用公共方法重寫 Object.clone(它是受保護的)。請參閱 Object.clone(),以獲得有關重寫此方法的詳細信息。 注意,此接口不 包含 clone 方法。因此,因為某個對象實現了此接口就克隆它是不可能的。即使 clone 方法是反射性調用的,也無法保證它將獲得成功。 從以下版本開始: JDK1.0 另請參見: CloneNotSupportedException, Object.clone()
現在可以知道的是,clone方法就是返回一個原對象的拷貝,默認走的是淺拷貝。克隆的目的是復制對象,但是新的對象是獨立於原來的對象的,一般我們克隆出來的對象都在一些屬性做了更改,這個時候需要小心一點,如果更改的屬性是引用數據類型,可能會影響到原來的對象,如果都是基本數據類型則不怕。使用clone方法的前提是繼承Cloneable接口,數組默認實現了Cloneable接口,默認走的是淺拷貝。
那么問題來了,什么是淺拷貝?什么是深拷貝呢?
2.淺克隆(shadow clone)
克隆就是復制一個對象的復本.若只需要復制對象的字段值(對於基本數據類型,如:int,long,float等,則復制值;對於復合數據類型僅復制該字段值,如數組變量則復制地址,對於對象變量則復制對象的reference。
例子:
- public class ShadowClone implements Cloneable{
- private int a; // 基本類型
- private int[] b; // 非基本類型
- // 重寫Object.clone()方法,並把protected改為public
- @Override
- public Object clone(){
- ShadowClone sc = null;
- try
- {
- sc = (ShadowClone) super.clone();
- } catch (CloneNotSupportedException e){
- e.printStackTrace();
- }
- return sc;
- }
- public int getA()
- {
- return a;
- }
- public void setA(int a)
- {
- this.a = a;
- }
- public int[] getB() {
- return b;
- }
- public void setB(int[] b) {
- this.b = b;
- }
- }
然后進行測試:
- public class Test{
- public static void main(String[] args) throws CloneNotSupportedException{
- ShadowClone c1 = new ShadowClone();
- //對c1賦值
- c1.setA(100) ;
- c1.setB(new int[]{1000}) ;
- System.out.println("克隆前c1: a="+c1.getA()+" b="+c1.getB()[0]);
- //克隆出對象c2,並對c2的屬性A,B,C進行修改
- ShadowClone c2 = (ShadowClone) c1.clone();
- //對c2進行修改
- c2.setA(50) ;
- int []a = c2.getB() ;
- a[0]=5 ;
- c2.setB(a);
- System.out.println("克隆前c1: a="+c1.getA()+" b="+c1.getB()[0]);
- System.out.println("克隆后c2: a="+c2.getA()+ " b[0]="+c2.getB()[0]);
- }
- }
結果為:
克隆前c1: a=100 b=1000
克隆前c1: a=100 b=5
克隆后c2: a=50 b[0]=5
c1和c2的對象模型:

可以看出,基本類型可以使用淺克隆,而對於引用類型,由於引用的是內容相同,所以改變c2實例對象中的屬性就會影響到c1。所以引用類型需要使用深克隆。另外,在開發一個不可變類的時候,如果這個不可變類中成員有引用類型,則就需要通過深克隆來達到不可變的目的。
3.深克隆(deep clone)
深克隆與淺克隆的區別在於對復合數據類型的復制。若對象中的某個字段為復合類型,在克隆對象的時候,需要為該字段重新創建一個對象。
例子:
- public class DeepClone implements Cloneable {
- private int a; // 基本類型
- private int[] b; // 非基本類型
- // 重寫Object.clone()方法,並把protected改為public
- @Override
- public Object clone(){
- DeepClone sc = null;
- try
- {
- sc = (DeepClone) super.clone();
- int[] t = sc.getB();
- int[] b1 = new int[t.length];
- for (int i = 0; i < b1.length; i++) {
- b1[i] = t[i];
- }
- sc.setB(b1);
- } catch (CloneNotSupportedException e){
- e.printStackTrace();
- }
- return sc;
- }
- public int getA()
- {
- return a;
- }
- public void setA(int a)
- {
- this.a = a;
- }
- public int[] getB() {
- return b;
- }
- public void setB(int[] b) {
- this.b = b;
- }
- }
結果為:
克隆前c1: a=100 b=1000
克隆前c1: a=100 b=1000
克隆后c2: a=50 b[0]=5
對象模型:

上面是copy的,自己敲一敲:
兩個准備的類:
class Person implements Cloneable{ @Override protected Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } String name; int age; Job job; 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 Job getJob() { return job; } public void setJob(Job job) { this.job = job; } @Override public String toString(){ return "name: " + name + ",age: " + age + ",job: " + job; } } class Job{ String jobName; String address; public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
public class CloneTest {
@Test
public void shaowClone() throws Exception{
Person p1 = new Person();
p1.setName("guo");
p1.setAge(22);
Job job = new Job();
job.setJobName("IT");
job.setAddress("shanghai");
p1.setJob(job);
Person p2 = p1.clone();
System.out.println(p1.toString());
System.out.println(p2.toString());
p2.getJob().setJobName("programmer");
System.out.println(p1.getJob().getJobName());
}
得到結果:
name: guo,age: 22,job: test.Job@4f2410ac
name: guo,age: 22,job: test.Job@4f2410ac
programmer
淺拷貝,就是Object默認的clone方法,完全的copy了這個類,基本數據類型copy了值,引用數據類型copy的是對象的引用,所以如果要對對象進行修改,可以使用深拷貝。
}
所謂的深拷貝,就是自己重寫了一下clone方法,將引用變量變成值傳遞而不是引用傳遞。
修改的代碼;
@Override protected Person clone() throws CloneNotSupportedException { Person ectype = (Person) super.clone(); Job tmp = new Job(); tmp.setJobName(ectype.getJob().getJobName()); tmp.setAddress(ectype.getJob().getAddress()); ectype.setJob(tmp); return ectype; }
測試代碼:
@Test
public void shaowClone() throws Exception{
Person p1 = new Person();
p1.setName("guo");
p1.setAge(22);
Job job = new Job();
job.setJobName("IT");
job.setAddress("shanghai");
p1.setJob(job);
Person p2 = p1.clone();
System.out.println(p1.toString());
System.out.println(p2.toString());
p2.getJob().setJobName("programmer");
System.out.println(p2.getJob().getJobName());
System.out.println(p1.getJob().getJobName());
}
結果:
over
