Java深度克隆问题

时间:2014-03-30 03:42:27

标签: java constructor clone

我正在学习有关对象克隆的Java。我很困惑浅层克隆和深度克隆。以下是 Core 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();
    }
}

}  

在这种情况下,原始对象和克隆对象的输出是相同的。由于我没有克隆可变字段,因此对克隆对象所做的更改将影响原始对象。但是当我将方法setHireDay更改为:

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

我确实更改了克隆对象中字段hireDay的值,但它不会影响原始对象。我不知道为什么

1 个答案:

答案 0 :(得分:1)

在更改后的setHireDay方法中," hireDay"变量指向另一个内存位置,而在第一个setHireDay方法中,内存位置不变(但它引用的值被更改)。它有助于考虑对象变量,例如" hireDay"作为指定内存地址(a.k.a.指针)的原始长值。在该存储器地址处存储实际的对象数据(如" 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;
}

}
相关问题