我正在学习对象深度克隆,我有一个带有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方法获取对象的单个实例的原则,然后我决定稍后复制该对象。
答案 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");