Java克隆对象

在这篇文章中,将学习java克隆对象或java中的克隆。 Java Object类附带了原生 clone()方法,该方法返回现有实例的副本。

要使用java对象克隆方法,必须实现接口java.lang.Cloneable,以便它不会在运行时抛出CloneNotSupportedException。对象克隆也是受保护的方法,因此要重写它以与其他类一起使用。

下面来看一个例子。

 package com.test.cloning;  import java.util.HashMap; import java.util.Iterator; import java.util.Map;  public class Employee implements Cloneable {      private int id;      private String name;      private Map<String, String> props;      public int getId() {         return id;     }      public void setId(int id) {         this.id = id;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public Map<String, String> getProps() {         return props;     }      public void setProps(Map<String, String> p) {         this.props = p;     }       @Override      public Object clone() throws CloneNotSupportedException {      return super.clone();      }  } 

请注意,这里使用Object的clone()实现,因此必须要实现Cloneable接口。用一个简单的程序测试clone对象示例。

 package com.test.cloning;  import java.util.HashMap; import java.util.Map;  public class CloningTest {      public static void main(String[] args) throws CloneNotSupportedException {          Employee emp = new Employee();          emp.setId(1);         emp.setName("Pankaj");         Map<String, String> props = new HashMap<>();         props.put("salary", "10000");         props.put("city", "Bangalore");         emp.setProps(props);          Employee clonedEmp = (Employee) emp.clone();          // Check whether the emp and clonedEmp attributes are same or different         System.out.println("emp and clonedEmp == test: " + (emp == clonedEmp));          System.out.println("emp and clonedEmp HashMap == test: " + (emp.getProps() == clonedEmp.getProps()));          // Lets see the effect of using default cloning          // change emp props         emp.getProps().put("title", "CEO");         emp.getProps().put("city", "New York");         System.out.println("clonedEmp props:" + clonedEmp.getProps());          // change emp name         emp.setName("new");         System.out.println("clonedEmp name:" + clonedEmp.getName());      }  } 

上面的克隆示例将产生以下输出:

emp and clonedEmp == test: false emp and clonedEmp HashMap == test: true clonedEmp props:{city=New York, salary=10000, title=CEO} clonedEmp name:Pankaj 

如果Employee类不实现Cloneable接口,则上面的程序将抛出java.lang.CloneNotSupportedException运行时异常。

Exception in thread "main" java.lang.CloneNotSupportedException: com.test.cloning.Employee     at java.lang.Object.clone(Native Method)     at com.journaldev.cloning.Employee.clone(Employee.java:41)     at com.journaldev.cloning.CloningTest.main(CloningTest.java:19) 

下面来看看第一个输出,并了解Object的clone()方法发生了什么,以及是否存在问题。

  1. emp and clonedEmp == test: false,因此empclonedEmp是两个不同的对象,而不是指同一个对象。 这符合java克隆对象的要求。

  2. emp and clonedEmp HashMap == test: true,因此empclonedEmp对象变量都引用同一个对象。 这带来了克隆的严重问题,接下来我们将看到。

  3. clonedEmp props:{city=New York, salary=10000, title=CEO},请注意,没有对clonedEmp属性进行任何更改,但它们仍然被更改,因为empclonedEmp变量都引用了同一个对象。 这是一个严重的问题,因为java中的默认克隆不会创建完全分离的对象。 这可能会导致不需要的结果,因此需要正确覆盖java克隆对象方法。

  4. clonedEmp name:Pankaj,这里发生了什么? 我们更改了emp名称,但是clonedEmp名称没有更改。这是因为String是不可变的。 因此,当设置emp名称时,将创建一个新字符串,并在this.name = name;中更改emp名称引用。 因此clonedEmp名称保持不变。 也会发现任何原始变量类型的类似行为。 因此,只要在对象中只有原始和不可变变量,就可以使用java clone对象的默认方法。

浅克隆
java clone对象的默认实现是使用浅拷贝,类似下面使用反射。

 @Override  public Object clone() throws CloneNotSupportedException {       Employee e = new Employee();      e.setId(this.id);      e.setName(this.name);      e.setProps(this.props);      return e; } 

深度克隆
在深度克隆中,必须逐个复制字段。可以覆盖下面的克隆方法进行深度克隆。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/264078.html

(0)
上一篇 2022年6月6日 23:46
下一篇 2022年6月6日 23:50

相关推荐

发表回复

登录后才能评论