java中clone方法

Cloning is the process of creating a copy of an Object. Java Object class comes with native clone() method that returns the copy of the existing instance.

克隆是创建对象副本的过程。 Java Object类带有本机clone()方法,该方法返回现有实例的副本。

Since Object is the base class in Java, all objects by default support cloning.

由于Object是Java中的基类,因此默认情况下所有对象都支持克隆。

Java对象克隆 (Java Object Cloning)

If you want to use Java Object clone() method, you have to implement the java.lang.Cloneable marker interface. Otherwise, it will throw CloneNotSupportedException at runtime.

如果要使用Java Object clone()方法,则必须实现java.lang.Cloneable标记接口。 否则,它将在运行时引发CloneNotSupportedException

Also Object clone is a protected method, so you will have to override it.

同样,对象克隆也是受保护的方法 ,因此您必须重写它。

Let’s look at Object cloning in Java with an example program.

让我们来看一个示例程序中的Java对象克隆。

package com.journaldev.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;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}}

We are using Object clone() method, so we have implemented the Cloneable interface. We are calling the superclass clone() method i.e. Object clone() method.

我们使用的是Object clone()方法,因此我们实现了Cloneable 接口 。 我们正在调用超类clone()方法,即Object clone()方法。

使用对象clone()方法 (Using Object clone() Method)

Let’s create a test program to use the object clone() method to create a copy of the instance.

让我们创建一个测试程序,以使用对象clone()方法创建实例的副本。

package com.journaldev.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 differentSystem.out.println("emp and clonedEmp == test: " + (emp == clonedEmp));System.out.println("emp and clonedEmp HashMap == test: " + (emp.getProps() == clonedEmp.getProps()));// Let's see the effect of using default cloning// change emp propsemp.getProps().put("title", "CEO");emp.getProps().put("city", "New York");System.out.println("clonedEmp props:" + clonedEmp.getProps());// change emp nameemp.setName("new");System.out.println("clonedEmp name:" + clonedEmp.getName());}}

Output:

输出:

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

运行时发生CloneNotSupportedException (CloneNotSupportedException at Runtime)

If our Employee class won’t implement Cloneable interface, the above program will throw CloneNotSupportedException runtime exception.

如果我们的Employee类不会实现Cloneable接口,则上述程序将抛出CloneNotSupportedException运行时异常 。

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

了解对象克隆 (Understanding Object Cloning)

Let’s look into the above output and understand what’s happening with Object clone() method.

让我们看一下上面的输出,并了解Object clone()方法的情况。

  1. emp and clonedEmp == test: false: It means that emp and clonedEmp are two different objects, not referring to the same object. This is in agreement with the java object cloning requirement.emp and clonedEmp == test: false :这意味着emp和clonedEmp是两个不同的对象,而不是引用同一对象。 这与Java对象克隆要求一致。
  2. emp and clonedEmp HashMap == test: true: So both emp and clonedEmp object variables refer to the same object. This can be a serious data integrity issue if we change the underlying object value. Any change in the value might get reflected to the cloned instance too.emp and clonedEmp HashMap == test: true :因此emp和clonedEmp对象变量都引用同一对象。 如果我们更改基础对象值,这可能是一个严重的数据完整性问题。 值的任何更改也可能会反映到克隆的实例中。
  3. clonedEmp props:{city=New York, salary=10000, title=CEO}: We didn’t make any change in clonedEmp properties, but still, they got changed because both emp and clonedEmp variables are referring to the same object.This is happening because the default Object clone() method creates a shallow copy. It can be a problem when you want to create totally detached objects through cloning process. This can lead to unwanted results, hence the need to properly override the Object clone() method.clonedEmp props:{city=New York, salary=10000, title=CEO} :我们没有对clonedEmp属性进行任何更改,但是仍然更改了它们,因为emp和clonedEmp变量都指向同一个对象。这是发生这种情况是因为默认的Object clone()方法创建了一个浅表副本。 当您要通过克隆过程创建完全分离的对象时,可能会出现问题。 这可能会导致不想要的结果,因此需要正确地重写Object clone()方法。
  4. clonedEmp name:Pankaj: What happened here?We changed the emp name but clonedEmp name didn’t change. It’s because String is immutable. So when we are setting emp name, a new string is created and emp name reference is changed in this.name = name;.Hence clonedEmp name remains unchanged. You will find similar behavior for any primitive variable types too. So we are good with java object default cloning as long as we have only primitive and immutable variables in the object.clonedEmp name:Pankaj :这里发生了什么?我们更改了emp名称,但clonedEmp名称未更改。 这是因为String是不可变的 。 因此,当我们设置emp名称时,将创建一个新字符串,并在this.name = name;更改emp名称引用this.name = name; 。因此clonedEmp名称保持不变。 对于任何原始变量类型,您也会发现类似的行为。 因此,只要对象中只有原始变量和不可变变量,我们就擅长使用Java对象默认克隆。

对象克隆类型 (Object Cloning Types)

There are two types of object cloning – shallow cloning, and deep cloning. Let’s understand each of them and find out the best way to implement cloning in our Java programs.

有两种类型的对象克隆–浅克隆和深克隆。 让我们理解它们中的每一个,并找出在我们的Java程序中实现克隆的最佳方法。

1.浅克隆 (1. Shallow Cloning)

The default implementation of Java Object clone() method is using shallow copy. It’s using reflection API to create the copy of the instance. The below code snippet showcase the shallow cloning implementation.

Java Object clone()方法的默认实现是使用浅表复制。 它使用反射 API创建实例的副本。 下面的代码片段展示了浅层克隆实现。

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

2.深克隆 (2. Deep Cloning)

In deep cloning, we have to copy fields one by one. If we have a field with nested objects such as List, Map, etc. then we have to write the code to copy them too one by one. That’s why it’s called deep cloning or deep copy.

在深度克隆中,我们必须一一复制字段。 如果我们有一个包含嵌套对象(例如List,Map等)的字段,那么我们必须编写代码以将它们也一张一张地复制。 这就是为什么将其称为深度克隆或深度复制。

We can override the Employee clone method like the following code for deep cloning.

我们可以像下面的代码那样覆盖Employee克隆方法,以进行深度克隆。

public Object clone() throws CloneNotSupportedException {Object obj = super.clone(); //utilize clone Object methodEmployee emp = (Employee) obj;// deep cloning for immutable fieldsemp.setProps(null);Map<String, String> hm = new HashMap<>();String key;Iterator<String> it = this.props.keySet().iterator();// Deep Copy of field by fieldwhile (it.hasNext()) {key = it.next();hm.put(key, this.props.get(key));}emp.setProps(hm);return emp;
}

With this clone() method implementation, our test program will produce the following output.

使用此clone()方法实现,我们的测试程序将产生以下输出。

emp and clonedEmp == test: false
emp and clonedEmp HashMap == test: false
clonedEmp props:{city=Bangalore, salary=10000}
clonedEmp name:Pankaj

In most of the cases, this is what we want. The clone() method should return a new object totally detached from the original instance.

在大多数情况下,这就是我们想要的。 clone()方法应返回一个与原始实例完全分离的新对象。

So if you are thinking to use Object clone and cloning in your program, do it wisely and override it properly by taking care of mutable fields.

因此,如果您打算在程序中使用对象克隆和克隆,请明智地进行操作,并通过照顾可变字段来适当地覆盖它。

It could be a daunting task if your class extends other class that in turn extends other class and so on. You will have to go all the way in the Object inheritance hierarchy to take care of the deep copy of all the mutable fields.

如果您的课程扩展了其他课程,又扩展了其他课程,这可能是一项艰巨的任务。 您将必须在对象继承层次结构中进行所有操作,以照顾所有可变字段的深层副本。

使用序列化克隆? (Cloning using Serialization?)

One way to easily perform deep cloning is through serialization. But serialization is an expensive procedure and your class should implement Serializable interface. All the fields and superclasses must implement Serializable too.

轻松执行深度克隆的一种方法是序列化 。 但是序列化是一个昂贵的过程,您的类应实现Serializable接口。 所有字段和超类也必须实现Serializable。

使用Apache Commons Util (Using Apache Commons Util)

If you are already using Apache Commons Util classes in your project and your class is serializable, then use the below method.

如果您已在项目中使用Apache Commons Util类,并且该类可序列化,则使用以下方法。

Employee clonedEmp = org.apache.commons.lang3.SerializationUtils.clone(emp);

复制构造函数以进行克隆 (Copy Constructor for Cloning)

We can define a copy constructor to create a copy of the object. Why to depend on the Object clone() method at all?

我们可以定义一个复制构造函数来创建对象的副本。 为什么要完全依赖Object clone()方法?

For example, we can have an Employee copy constructor like the following code.

例如,我们可以有一个类似于以下代码的Employee复制构造函数。

public Employee(Employee emp) {this.setId(emp.getId());this.setName(emp.getName());Map<String, String> hm = new HashMap<>();String key;Iterator<String> it = emp.getProps().keySet().iterator();// Deep Copy of field by fieldwhile (it.hasNext()) {key = it.next();hm.put(key, emp.getProps().get(key));}this.setProps(hm);}

Whenever we need a copy of employee object, we can get it using Employee clonedEmp = new Employee(emp);.

每当我们需要员工对象的副本时,都可以使用Employee clonedEmp = new Employee(emp);获得它Employee clonedEmp = new Employee(emp);

However writing copy constructor can be a tedious job if your class has a lot of variables, especially primitive and immutable.

但是,如果您的类具有很多变量,尤其是原始变量和不可变变量,那么编写拷贝构造函数可能是一项繁琐的工作。

Java对象克隆最佳实践 (Java Object Cloning Best Practices)

  1. Use default Object clone() method only when your class has primitives and immutable variables or you want shallow copy. In case of inheritance, you will have to check all the classes you are extending till the Object level.仅当您的类具有基元和不可变变量或需要浅表复制时,才使用默认的Object clone()方法。 在继承的情况下,您将必须检查所有扩展到对象级别的类。
  2. You can also define copy constructor if your class has mostly mutable properties.如果您的类主要具有可变属性,则还可以定义复制构造函数。
  3. Utilize Object clone() method by calling super.clone() in overridden clone method, then make necessary changes for deep copying of mutable fields.通过在重写的克隆方法中调用super.clone()来利用Object clone()方法,然后进行必要的更改以对可变字段进行深度复制 。
  4. If your class is serializable, you can use serialization for cloning. However, it will come with a performance hit, so do some benchmarking before using serialization for cloning.如果您的类可序列化,则可以使用序列化进行克隆。 但是,它将带来性能上的损失,因此在使用序列化进行克隆之前,请进行一些基准测试。
  5. If you are extending a class and it has defined clone method properly using deep copy, then you can utilize default clone method. For example, we have properly defined clone() method in Employee class as follows.
    @Override
    public Object clone() throws CloneNotSupportedException {Object obj = super.clone();Employee emp = (Employee) obj;// deep cloning for immutable fieldsemp.setProps(null);Map<String, String> hm = new HashMap<>();String key;Iterator<String> it = this.props.keySet().iterator();// Deep Copy of field by fieldwhile (it.hasNext()) {key = it.next();hm.put(key, this.props.get(key));}emp.setProps(hm);return emp;
    }

    We can create a child class and utilize the superclass deep cloning as follows.

    The EmployeeWrap class doesn’t have any mutable properties and it’s utilizing superclass clone() method implementation. If there are mutable fields, then you will have to take care of deep copying of only those fields.

    Here is a simple program to test if this way of cloning works fine or not.

    package com.journaldev.cloning;import java.util.HashMap;
    import java.util.Map;public class CloningTest {public static void main(String[] args) throws CloneNotSupportedException {EmployeeWrap empWrap = new EmployeeWrap();empWrap.setId(1);empWrap.setName("Pankaj");empWrap.setTitle("CEO");Map<String, String> props = new HashMap<>();props.put("salary", "10000");props.put("city", "Bangalore");empWrap.setProps(props);EmployeeWrap clonedEmpWrap = (EmployeeWrap) empWrap.clone();empWrap.getProps().put("1", "1");System.out.println("empWrap mutable property value = "+empWrap.getProps());System.out.println("clonedEmpWrap mutable property value = "+clonedEmpWrap.getProps());}}

    Output:

    So it worked perfectly as we expected.

    @Override
    public Object clone() throws CloneNotSupportedException {Object obj = super.clone();Employee emp = (Employee) obj;// deep cloning for immutable fieldsemp.setProps(null);Map<String, String> hm = new HashMap<>();String key;Iterator<String> it = this.props.keySet().iterator();// Deep Copy of field by fieldwhile (it.hasNext()) {key = it.next();hm.put(key, this.props.get(key));}emp.setProps(hm);return emp;
    }

    我们可以创建一个子类,并利用超类进行深度克隆,如下所示。

    EmployeeWrap类没有任何可变属性,并且正在使用超类clone()方法实现。 如果存在可变字段,那么您将只需要深度复制那些字段。

    这是一个简单的程序,用于测试这种克隆方式是否正常工作。

    package com.journaldev.cloning;import java.util.HashMap;
    import java.util.Map;public class CloningTest {public static void main(String[] args) throws CloneNotSupportedException {EmployeeWrap empWrap = new EmployeeWrap();empWrap.setId(1);empWrap.setName("Pankaj");empWrap.setTitle("CEO");Map<String, String> props = new HashMap<>();props.put("salary", "10000");props.put("city", "Bangalore");empWrap.setProps(props);EmployeeWrap clonedEmpWrap = (EmployeeWrap) empWrap.clone();empWrap.getProps().put("1", "1");System.out.println("empWrap mutable property value = "+empWrap.getProps());System.out.println("clonedEmpWrap mutable property value = "+clonedEmpWrap.getProps());}}

    输出:

    因此,它可以按我们预期的那样完美运行。

That’s all about Object cloning in java. I hope you got some idea about Java Object clone() method and how to properly override it without any adverse effect.

这就是Java中的对象克隆。 我希望您对Java Object clone()方法以及如何正确重写它而没有任何不利影响有所了解。

GitHub Repository.GitHub Repository下载该项目。

Reference: API Doc for Object clone

参考: 用于对象克隆的API Doc

翻译自: https://www.journaldev.com/60/java-clone-object-cloning-java

java中clone方法

java中clone方法_Java Object clone()方法– Java中的克隆相关推荐

  1. java clone方法_Java Calendar clone()方法与示例

    java clone方法 日历类clone()方法 (Calendar Class clone() method) clone() method is available in java.util p ...

  2. java clone方法_JAVA对象clone方法代码实例解析

    1.Cloneable接口 这个接口一个方法都没有,但是要使用clone方法,就必须实现这个接口,否则抛出CloneNotSupportedException异常 2.clone方法的返回值 先附上两 ...

  3. [转载] java clone方法_Java Calendar clone()方法与示例

    参考链接: Java中的Clone()方法 java clone方法 日历类clone()方法 (Calendar Class clone() method) clone() method is av ...

  4. java ldap操作实例_Java Spring Security示例教程中的2种设置LDAP Active Directory身份验证的方法...

    java ldap操作实例 LDAP身份验证是世界上最流行的企业应用程序身份验证机制之一,而Active Directory (Microsoft为Windows提供的LDAP实现)是另一种广泛使用的 ...

  5. java wait 参数_Java Object wait()方法

    Java Object wait()方法 java.lang.Object.wait(long timeout, int nanos) 导致当前线程等待,直到其他线程调用此对象的 notify() 方 ...

  6. java替换换行符_Java的replace替换字符串中的回车换行符的方法

    Java的replace替换字符串中的回车换行符的方法 导语:Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大 ...

  7. java中math的方法_Java Math所有方法

    首页 > 基础教程 > 常用类 > 常用 Number & Math类 Java Math所有方法 Math类包含完成基本数学函数所需的方法.这些方法分为三类:三角函数方法. ...

  8. java方法重载和重载方法_Java 8的方法参考进一步限制了重载

    java方法重载和重载方法 方法重载一直是一个充满喜忧参半的话题. 我们已经在博客上介绍了它,并介绍了几次警告: 您会后悔对Lambdas应用重载! 保持干燥:方法重载 为什么每个人都讨厌操作员超载 ...

  9. java 调用对象的方法_JAVA调用对象方法的执行过程

    JAVA调用对象方法的执行过程: ①.编译器查看对象的声明类型和方法名.假设调用x.f(parameter),  且隐式参数x声明为C类型的对象,有可能在C对象中存在多个参数类型和参数个数不同的f的方 ...

最新文章

  1. 2021湖南高考艺考成绩查询,2021届湖南艺考生联考成绩查询时间安排
  2. js 操作 select option
  3. 23种设计模式中的解释器模式
  4. vuecli启动的服务器位置,在vue cli 3生成的项目中启动dev服务器
  5. SAP Spartacus visible-focus是如何施加到HTML element上的
  6. 模拟退火求解TSP问题
  7. 人工智能AI实战100讲(十)-一文读懂推荐系统负采样
  8. 多线程中 start()和run()方法的区别
  9. 信息学奥赛一本通 提高篇 第6章 平衡树Treap
  10. APIView和View的区别
  11. JDK的KeyTool和KeyStore等加密相关
  12. 【观察】从实践到赋能再到引领,华为释放数据中心无限潜力
  13. 数据的结构分类:结构化数据,半结构化数据以及非结构化数据
  14. 单细胞测序数据下载和预处理
  15. 7zip打不开wim文件
  16. 重力感应失灵/更新win10后不能自动旋转屏幕
  17. java 使用7z进行解压_java调用7zip解压压缩包的实例
  18. 基于node.js和Vue的运动装备网上商城
  19. Vue安装并使用axios发送请求
  20. 会飞的鲨鱼?记遥控氦气球的诞生

热门文章

  1. maven+springMvc+velocity
  2. [转载] python面向对象编程实例
  3. `ll/sc` 指令在`linux`中的软件实现
  4. 清空visual studio 开发缓存
  5. day17 Python 反射获取内容和修改内容
  6. bzoj1079 [SCOI2008]着色方案
  7. OSGi.NET 学习笔记 [模块化和插件化][概念]
  8. uva10340 Ail in All
  9. 关于“抵制”易语言的通告
  10. CV学习笔记-边缘提取