原文地址:http://leihuang.org/2014/11/14/java-clone/

In java, it essentially means the ability to create an object with similar state as the original object.

什么是clone

字典中的意思就是复制(强调跟原来的一模一样)。

*By default, java cloning is ‘field by field copy’ *.由于Object类不知道详细类的结构,无法确定哪个clone方法将被调用。

所以JVM规定clone,做例如以下操作。

  1. 假设这个类仅仅有原始数据类型成员的话。那么须要创建一个一模一样的对象,而且返回这个新对象的引用。
  2. 假设这个类包括了不论什么类类型成员的话,那么仅仅有这些成员的对象引用被复制。且原始对象和克隆对象的成员的引用将指向同一个对象。

翻译的不好。%>_<%

  1. If the class has only primitive data type members then a completely new copy of the object will be created and the reference to the new object copy will be returned.
  2. If the class contains members of any class type then only the object references to those members are copied and hence the member references in both the original object as well as the cloned object refer to the same object.

除了上面两条默认的操作之外。你也能够重载clone方法,制定一套自己的clone方法。


java中clone规则

每种支持clone的语言都有它自己的规则,java也不例外。java中假设一个类需要支持clone的话。必需要做例如以下事情:

  1. 你必须继承Cloneable接口---Cloneable interface is broken in java。otherwise throws java.lang.CloneNotSupportedException.
  2. 必须重写Object类中的clone()方法
/*
Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
The general intent is that, for any object x, the expression:
1) x.clone() != x will be true
2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
3) x.clone().equals(x) will be true, this is not an absolute requirement.
*/
protected native Object [More ...] clone() throws CloneNotSupportedException;

  1. 第一条表明,clone对象分配有独立的内存地址。
  2. 第二条表明,原始的和克隆的对象应该具有同样类型,但这不是必须的
  3. 第三条表明。原始的和克隆的对象调用equals方法的话,应该时相等的。但这不是必须的。

以下我们通过样例来分析:

class Father implements Cloneable{
private int age ;
private String name ;
private Son son ; public Father(int age,String name,Son son){
this.age = age ;
this.name = name ;
this.son = son ;
} public Son getSon(){
return this.son ;
} @Override
protected Object clone()throws CloneNotSupportedException{
return super.clone() ;
}
}
class Son{
private int age ;
private String name ; public Son(int age ,String name){
this.age = age ;
this.name = name ;
} public void setName(String name){
this.name = name ;
}
public String getName(){
return this.name ;
}
}
public class CloneDemo {
public static void main(String args[]) throws CloneNotSupportedException{
Son s = new Son(10,"Jack") ;
Father fa = new Father(40,"Tom",s) ;
Father clonedFa = (Father) fa.clone() ; System.out.println(fa!=clonedFa);
System.out.println(clonedFa.getClass()==fa.getClass());
System.out.println(clonedFa.equals(fa)); //now we change the fa's son name by the clonedFa's son name
clonedFa.getSon().setName("Jay");
System.out.println(fa.getSon().getName());
}
}
/*print:
true
true
false
Jay
*/

上面的代码中能够看出。原始的和克隆的Father类对象。拥有指向同一对象的两个引用。所以能够通过改变clonedFa中的Son来改变fa中Son对象。这就时所谓的浅拷贝.以下我们具体讨论一下浅拷贝和深拷贝。

浅拷贝(Shallow Cloning)

这是java中默认的实现。上面的样例中就是浅拷贝。不创建一个新的克隆拷贝对象Son,而是直接两个引用指向同一对象。

深拷贝

If we want a clone which is independent of original and making changes in clone should not affect original.you can try Deep Cloning.

we change the clone() method in the Father class .

@Override
protected Object clone() throws CloneNotSupportedException {
Father fa = (Father)super.clone();
fa.setSon((Son)fa.getSon().clone());
return fa;
}

and we need Override the clone() method in the Son class. like this.

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

如今我们已经实现深拷贝了。

拷贝构造函数

拷贝构造函数时一种特殊的构造器。它讲自己的类类型作为參数。我们传递一个类的实例给拷贝构造函数。然后它将返回一个新的类实例。lets see this in example

public class PointOne {
private Integer x;
private Integer y; public PointOne(PointOne point){
this.x = point.x;
this.y = point.y;
}
}

假设要继承它的话,则须要复制子类的參数,和传递參数给父类的构造器。

例如以下:

public class PointTwo extends PointOne{
private Integer z; public PointTwo(PointTwo point){
super(point); //Call Super class constructor here
this.z = point.z;
}
}

以下是測试代码:

class Test
{
public static void main(String[] args)
{
PointOne one = new PointOne(1,2);
PointTwo two = new PointTwo(1,2,3); PointOne clone1 = new PointOne(one);
PointOne clone2 = new PointOne(two); //Let check for class types
System.out.println(clone1.getClass());
System.out.println(clone2.getClass());
}
}
Output:
class corejava.cloning.PointOne
class corejava.cloning.PointOne

你也能够使用静态工厂的方法来实现它。

public class PointOne {
private Integer x;
private Integer y; public PointOne(Integer x, Integer y)
{
this.x = x;
this.y = y;
} public PointOne copyPoint(PointOne point) throws CloneNotSupportedException
{
if(!(point instanceof Cloneable))
{
throw new CloneNotSupportedException("Invalid cloning");
}
//Can do multiple other things here
return new PointOne(point.x, point.y);
}
}

Cloning with serialization

这是例外一种深拷贝的方法。这里就不多讲了,具体见:A mini guide for implementing serializable interface in java

best practices

1) When you don’t know whether you can call the clone() method of a particular class as you are not sure if it is implemented in that class, you can check with checking if the class is instance of “Cloneable” interface as below.

if(obj1 instanceof Cloneable){
obj2 = obj1.clone();
}
//Dont do this. Cloneabe dont have any methods
obj2 = (Cloneable)obj1.clone();

2) No constructor is called on the object being cloned. As a result, it is your responsibility, to make sure all the members have been properly set. Also, if you are keeping track of number of objects in system by counting the invocation of constructors, you
got a new additional place to increment the counter.

Reference:

  1. A guide to object cloning in java
  2. Effective--Java Item 11: Override clone judiciously(讲的更具体,各种clone方式的优缺点都讲了)

2014-11-14 15:48:12

Brave,Happy,Thanksgiving !

版权声明:本文博主原创文章。博客,未经同意不得转载。

j详细说明ava于clone办法的更多相关文章

  1. 使用 IntelliJ IDEA 2016和Maven创建Java Web项目的详细步骤及相关问题解决办法

    Maven简介 相对于传统的项目,Maven 下管理和构建的项目真的非常好用和简单,所以这里也强调下,尽量使用此类工具进行项目构建, 它可以管理项目的整个生命周期. 可以通过其命令做所有相关的工作,其 ...

  2. jquery的clone办法bug修复

    发现测试,textarea和select的jquery的clone有问题的方法,textarea和select值clone时间会输.这是发现jquery一个bug,上不了的能够看下代码.比較简单.就是 ...

  3. j疑难杂症:ava.lang.NoSuchMethodError: com.opensymphony.xwork2.util.finder.ClassFinder.<init>

    严重: Exception starting filter struts2java.lang.NoSuchMethodError: com.opensymphony.xwork2.util.finde ...

  4. j经常使用ava应用server

    什么是应用server它?它主要提供的执行环境的应用程序,为组件提供服务. 要了解更多关于,您可以查看我的博客:何为容器? Java 的应用server非常多,从功能上分为两类:WEB 应用serve ...

  5. Linux 查找指定名称的进程并显示进程详细信息

    实际应用中可能有这样的场景:给定一个进程名称特征串,查找所有匹配该进程名称的进程的详细信息. 解决的办法是: (1) 先用pgrep [str] 命令进行模糊匹配,找到匹配该特征串的进程ID: (2) ...

  6. Mysql 死锁的详细分析方法

    用数据库的时候,偶尔会出现死锁,针对我们的业务系统,出现死锁的直接结果就是系统卡顿.客户找事儿,所以我们也在想尽全力的消除掉数据库的死锁.出现死锁的时候,如果只是想解锁,用show full proc ...

  7. [C#] .NET Core项目修改project.json来引用其他目录下的源码等文件的办法 & 解决多框架时 project.json 与 app.config冲突的问题

    作者: zyl910 一.缘由 项目规模大了后,经常会出现源码文件分布在不同目录的情况,但.NET Core项目默认只有项目目录下的源码文件,且不支持"Add As Link"方式 ...

  8. java对象的深浅clone

    在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int.double.byte.boolean.char等简单数据类型,引用类型包括类.接口.数组等复杂类型. 浅克隆和深克隆 ...

  9. .NET Core项目修改project.json来引用其他目录下的源码等文件的办法 & 解决多框架时 project.json 与 app.config冲突的问题

    作者: zyl910 一.缘由 项目规模大了后,经常会出现源码文件分布在不同目录的情况,但.NET Core项目默认只有项目目录下的源码文件,且不支持“Add As Link”方式引入文件.这时需要手 ...

随机推荐

  1. ASP.NET Identity 系列笔记目录

    编写目的 混迹博客园已经有一段时间了,一直都是在学习各路大神的文章,自己却没有做出什么贡献,所以觉得应该写一点点内容和大家一起分享.但是本人实在才疏学浅,有心无力啊!正好最近在学习 Microsoft ...

  2. SpringMVC 中整合之JSON、XML

    每次看到好的博客我就想好好的整理起来,便于后面自己复习,同时也共享给网络上的伙伴们! 博客地址: springMVC整合Jaxb2.xStream:  http://www.cnblogs.com/h ...

  3. docker 私有仓库镜像的存储位置

    docker 私有仓库的镜像 是存储在5739360d1030 registry "docker-registry" 3 days ago Up 28 hours 0.0.0.0: ...

  4. The Hardest Problem Ever(字符串)

    The Hardest Problem Ever Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24039   Accept ...

  5. 浅谈POSIX线程的私有数据

    当线程中的一个函数需要创建私有数据时,该私有数据在对函数的调用之间保持一致,数据能静态地分配在存储器中,当我们采用命名范围也许可以实现它使用在函数或是文件(静态),或是全局(EXTERN).但是当涉及 ...

  6. DLL导出函数和类 之 __declspec(dllexport)

    可利用__declspec(dllexport)导出函数或类. 若要指定C类型约定导出,则需在前面加extern “C”. 若要导出函数,__declspec(dllexport) 关键字必须出现在调 ...

  7. JavaScript之怎样获取元素节点

    JavaScript获取元素节点一共有三种方法,分别是通过元素ID.通过标签名字和通过类名字来获取: 1.通过元素ID属性的ID值来获得元素对象-getElementById() DOM提供了一个名为 ...

  8. Java程序在向mysql中插入数据的时候出现乱码

    今天在往数据库中插入数据的时候中文字符在数据库中就出现了乱码?网上有各种说法,但是适合我的,最终解决我的问题的只有下面一种! 在创建数据库的时候,注意设置编码方式. CREATE DATABASE ` ...

  9. js中字符串方法

    字符串方法: 1. charAt(索引值)//通过索引值获取字符串中对应的值 例如: var str='sdf123'; alert(str.charAt(0));//结果弹出第一个索引对应的值:s

  10. Ubuntu 14.04 静态IP设置

    1. 编辑/etc/network/interfaces vim /etc/network/interfaces 2.将以下五项添加到/etc/network/interfaces中 Static d ...