我正在学习对象深度克隆,我有一个带有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;
}
}
Object deep copy test class
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");
从控制台输出中可以看到它反映到原始对象 . I assume this is because of the static call ? , and how do I overcome this ? 我违反了通过getInstance方法需要对象的单个实例的原则,然后我决定稍后复制该对象 .
4 回答
这就是JAVA Doc教程页面所说的内容:
克隆的对象
cloned
只是该类的另一个对象 . 它没有改变它没有引用的另一个对象 . 您的调用cloned.getInstance()
正在返回所有对象都可以访问的静态对象employee
,因为静态对象与Class
关联,而不是与任何特定对象关联 . 所以你调用cloned.getInstance().setName("Mark");
就等于Employee.employee.setName("Mark");
您正在
static
字段的Employee
实例上设置名称employee
并打印它
您可能希望实际更改
cloned
实例静态字段大致意味着它将由每个对象共享 . 无论您创建/克隆了多少对象,您的getInstance()调用都将返回相同的Employee .
因此,只要您将其名称设置为Mark,您将始终在控制台中获得Mark .
例如:
如果你在控制台中得到“Mark”,不要感到惊讶;)
有关实例和类(使用static关键字)成员之间差异的更详细信息,请查看此tutorial section
您将要序列化对象,然后反序列化它 . 在java中,反序列化可以保证创建一个新对象 . (与Classloader的工作方式有关) .
序列化对象时,它会对对象及其所有依赖项进行深层复制等 . 序列化可以通过多种方式使用,但一种方法是将对象转换为字节,以便可以通过线路发送(网络),或存储在磁盘上以保持持久性 . 您可以使用该行为执行内存中序列化/反序列化,并每次使用完全相同的内容(值)创建新对象,但引用与原始内容不同 .
这是我在某个应用程序中 生产环境 的方法: