2014-03-30 104 views
0

我正在學習關於對象克隆的Java。我真的很困惑淺層克隆和深層克隆。下面是Java核心Java深層克隆問題

public class Employee implements Cloneable { 
    private String name; 
    private Date hireDay; 

    public Employee(String n,double s) 
    { 
     this.name=n; 
     hireDay=new Date(); 
    } 
    public void setHireDay(int year,int month,int day) 
    { 
     Date newhireDay=new GregorianCalendar(year,month-1,day).getTime(); 
     hireDay.setTime(newhireDay.getTime()); 
    } 
    public Employee clone() throws CloneNotSupportedException 
    { 
     Employee cloned=(Employee) super.clone(); 
    //clone mutable fields 
    //cloned.hireDay=(Date) hireDay.clone(); 
     return cloned; 
    } 
    public String toString() 
    { 
    return "Employee[name=]"+ name+" salary= "+salary+" hireday.getTIme() "+hireDay+"]"; 
    } 
} 
public class cloneTest { 
    public static void main(String[] args) { 
    try{ 
     Employee original =new Employee("john"); 
     Employee cloned=original.clone(); 
     original.setHireDay(1993,2,22); 
     cloned.setHireDay(2000,11,22); 
     System.out.println("original="+original); 
     System.out.println("cloned= "+cloned); 
    } 
    catch(CloneNotSupportedException e){ 
     e.printStackTrace(); 
    } 
} 

} 

一個示例代碼在這種情況下,原始對象和克隆對象的輸出是same.Since我沒有克隆可變場,在克隆的對象所做的更改將影響原始對象。但是,當我改變方法setHireDay到這一點:

public void setHireDay(int year,int month,int day) 
    { 
    hireDay=new GregorianCalendar(year,month-1,day).getTime(); 
} 

我沒有改變場hireDay的價值在克隆的對象,但它不會影響原來的object.I不知道爲什麼

+0

「我真的被淺層克隆和深層克隆困惑了。」是的:)深度複製應該是這樣的,這種變化也不在源代碼中。這就是爲什麼它是一個「深層次」的副本:不僅創建了類的第二個實例,但其中的每個成員都是新創建的副本。 – deviantfan

+0

如果您正在學習有關克隆的知識,那麼您應該瞭解克隆的第一件事:它本質上已經破裂。所以,不要這樣做,除非你絕對必須這樣做。您可能會問,克隆的替代方案是什麼?使用不可變對象。您應該花一些時間閱讀如何在Java中創建不可變類。 – hfontanez

回答

1

在改變setHireDay方法「hireDay」變量指向另一個內存位置,而在第一個setHireDay方法中,內存位置保持不變(但其引用的值已更改)。它有助於將像「hireDay」這樣的對象變量看作指定內存地址的原始long值(也稱爲指針)。在這個存儲器地址中存儲實際的對象數據(如「hireDay」變量的時間值)。在hireDay = new Date()的情況下,存儲器地址被改變,而在hireDay.setTime(x)的情況下,存儲器地址保持不變,但所引用的值被改變。

下面的示例(將其作爲Java應用程序運行,並將輸出與源代碼進行比較)以及如何製作深拷貝與淺拷貝的示例。

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 
import java.util.Date; 
import java.util.GregorianCalendar; 

public class CloneTest implements Cloneable, Serializable { 
private static final long serialVersionUID = 5971741470680723802L; 

public static void main(String[] args) { 

    try { 
     CloneTest original = new CloneTest(); 

     System.out.println(); 
     System.out.println("### shallow clone"); 

     CloneTest cloned=original.clone(); 
     compare(original, cloned); 
     original.setHireDay(1993,2,22); 
     cloned.setHireDay(2000,11,22); 
     compare(original, cloned); 

     System.out.println(); 
     System.out.println("### shallow clone - mutable hiredate"); 

     cloned.hireDayMutable = true; 
     cloned.setHireDay(2002,11,22); 
     compare(original, cloned); 

     System.out.println(); 
     System.out.println("### deep clone"); 

     cloned = clone(original); 
     compare(original, cloned); 
     cloned.setHireDay(2004,11,22); 
     compare(original, cloned); 

    } catch(Exception e){ 
     e.printStackTrace(); 
    } 
} 

private Date hireDay; 
public boolean hireDayMutable; 

public CloneTest() { 
    super(); 
    hireDay=new Date(); 
    System.out.println("New instance"); 
} 

public void setHireDay(int year, int month, int day) { 

    if (hireDayMutable) { 
     hireDay = new GregorianCalendar(year,month-1,day).getTime(); 
    } else { 
     Date newhireDay = new GregorianCalendar(year,month-1,day).getTime(); 
     hireDay.setTime(newhireDay.getTime()); 
    } 
} 

public CloneTest clone() throws CloneNotSupportedException { 

    CloneTest cloned = (CloneTest)super.clone(); 
    return cloned; 
} 

public String toString() { 
    return "CloneTest[hireday=" + hireDay + "]"; 
} 

public static void compare(CloneTest original, CloneTest cloned) { 

    System.out.println(); 
    System.out.println("The same object : " + (cloned == original)); 
    System.out.println("The same hireDate: " + (cloned.hireDay == original.hireDay)); 
    System.out.println("original = " + original); 
    System.out.println("cloned = " + cloned); 
} 

/** 
* Clones an object by serializing and then unserializing it ("deep copy"). 
*/ 
@SuppressWarnings("hiding") 
public static <T> T clone(T o) { 
    return clone(o, 512); 
} 

@SuppressWarnings({ "unchecked", "hiding" }) 
public static <T> T clone(T o, int bufSize) { 
    return (T) unserialize(serialize(o, bufSize)); 
} 

public static byte[] serialize(Object o, int bufSize) { 

    ByteArrayOutputStream baos = new ByteArrayOutputStream(bufSize); 
    try { 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject((Serializable)o); 
     oos.close(); 
    } catch (IOException e) { 
     throw new RuntimeException(e); 
    } 
    byte[] ba = baos.toByteArray(); 
    // log.trace("Serialized size: {}", ba.length); 
    return ba; 
} 

public static Object unserialize(byte[] ba) { 

    Object o = null; 
    try { 
     ByteArrayInputStream bais = new ByteArrayInputStream(ba); 
     ObjectInputStream oin = new ObjectInputStream(bais); 
     o = oin.readObject(); 
    } catch (Exception e) { 
     throw new RuntimeException(e); 
    } 
    return o; 
} 

}