对象是克隆的,但静态引用仍然存在?

时间:2013-10-15 19:24:32

标签: java object clone static-methods

我正在学习对象深度克隆,我有一个带有getInstance方法的employee类,它返回一个单例,我正在克隆返回的对象.Below是类和测试类。

public class Employee  implements Serializable , Cloneable {

    public static Employee employee;

    private String name;

    private int age;


    private Employee(){


    }


    public Employee(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    protected Object clone() throws CloneNotSupportedException {

        return super.clone();

        }


    public static Employee getInstance(){

        if(employee == null ){
            employee = new Employee();
            return employee;
        }


        return employee;
    }


    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 class CopyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {



        try {

            Employee original = Employee.getInstance();

            original.setName("John");
            original.setAge(25);

            Employee cloned = (Employee)copy(original);

            System.out.println("Original -->"+Employee.getInstance().getName());

            cloned.getInstance().setName("Mark");

            System.out.println("Cloned -->"+cloned.getInstance().getName());

            System.out.println("Original -->"+Employee.getInstance().getName());

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    public static Object copy(Object orig) {
        Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return obj;
    }
}

输出

Original -->John
Cloned -->Mark
Original -->Mark

问题

尽管我克隆了原始对象以创建它的副本,

Employee cloned = (Employee)copy(original);

我通过调用

来修改克隆对象的属性
cloned.getInstance().setName("Mark");

从控制台输出中可以看到它反映到原始对象。 我认为这是因为静态调用?我如何克服这个问题?我是否违反了我需要通过getInstance方法获取对象的单个实例的原则,然后我决定稍后复制该对象。

4 个答案:

答案 0 :(得分:1)

您要在Employee字段static

employee个实例上设置名称
cloned.getInstance().setName("Mark");
      ^ static method call that returns the employee reference

并打印它

System.out.println("Cloned -->"+cloned.getInstance().getName());
                                      ^ static method call

您可能希望实际更改cloned实例

cloned.setName("Mark");
System.out.println("Cloned -->"+cloned.getName());

答案 1 :(得分:1)

静态字段大致意味着它将由每个对象共享。无论您创建/克隆了多少对象,您的getInstance()调用都将返回相同的Employee。

因此,只要您将其名称设置为Mark,您就会始终在控制台中获得Mark。

例如:

Employee me = new Employee();
Employee.getInstance().setName("Mark");
System.out.println("me employee name? " + me.getInstance().getName());

如果你在控制台中得到“Mark”,不要感到惊讶;)

有关实例和类(使用static关键字)成员之间差异的更详细信息,请查看此tutorial section

答案 2 :(得分:0)

您将要序列化对象,然后反序列化它。在java中,反序列化可以保证创建一个新对象。 (与Classloader的工作方式有关。)

当您序列化对象时,它会执行对象的深层复制及其所有依赖项等。序列化可以通过多种方式使用,但一种方法是将对象转换为字节,以便可以将其发送到电线(网络),或存储在磁盘上以保持持久性。您可以使用该行为进行内存中序列化/反序列化,并每次使用完全相同的内容(值)创建一个新对象,但引用的内容与原始内容不同。

这是我在某个应用程序中正在制作的方法:

/**
 * Clones an object creating a brand new
 * object by value of input object. Accomplishes this
 * by serializing the object, then deservializing it.
 * 
 * @param obj Input Object to clone
 * @return a new List<Product> type cloned from original.
 * @throws IOException If IOException
 * @throws ClassNotFoundException If ClassNotFoundException
 */
private static List<Product> cloneProdList(Object obj) throws IOException, ClassNotFoundException {

    java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
    java.io.ObjectOutputStream obj_out = new java.io.ObjectOutputStream(bos);
    obj_out.writeObject(obj);

    java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(bos.toByteArray());
    java.io.ObjectInputStream obj_in = new java.io.ObjectInputStream(bis);

    @SuppressWarnings("unchecked")
    List<Product> newObj = (List<Product>)obj_in.readObject();

    bos.close();
    bis.close();
    obj_out.close();
    obj_in.close();

    return newObj;
}

答案 3 :(得分:0)

这是JAVA Doc教程页面所说的内容:

  

调用在其声明中具有static修饰符的字段   静态字段或类变量。他们与班级有关,   而不是与任何对象。该类的每个实例都共享一个   类变量,它位于内存中的一个固定位置。任何对象   可以更改类变量的值,但类变量也可以   在不创建类的实例的情况下进行操作。

克隆对象cloned只是该类的另一个对象。它没有改变它没有引用的另一个对象。您的调用cloned.getInstance()返回所有对象都可以访问的静态对象employee,因为静态对象与Class关联,而不是与任何特定对象关联。因此,您致电cloned.getInstance().setName("Mark");只相当于Employee.employee.setName("Mark");