解读克隆

编程过程中我们常常遇到如下情况: 假设有一个对象object,在某处又需要一个跟object一样的实例object2,强调的是object和object2是两个独立的实例,只是在 开始的时候,他们是具有相同状态的(属性字段的值都相同),跟同卵双胞胎很相似。遇到这种情况的做法一般是,重新new一个对象object2,将 object的字段值赋予object2,可以说这种方法很土,我们可以使用clone方法克隆出一个跟object一样的object2,很高效。

误区:有人认为直接将对象object的引用赋予object2就解决问题了,即:object2=object; 这样的话两个引用仍然指向的是同一个对象,不是两个对象。

Java中跟克隆有关的两个类分别是Cloneable接口和Object类中的clone方法,通过两者的协作来实现克隆。首先看一下java api doc中关于Cloneable接口和Object类中的clone方法的描述:

java.lang.Cloneable 接口(以下源引JavaTM 2 Platform Standard Ed. 5.0 API DOC)

此类实 现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。 如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException异常。 

按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。 

注意,此接口不包含 clone 方法。因此,因为某个对象实现了此接口就克隆它是不可能的。即使 clone 方法是反射性调用的,也无法保证它将获得成功。

解读:Cloneable接口没有任何方法, 仅是个标志接口(tagging interface),若要具有克隆能力,实现Cloneable接口的类必须重写从Object继承来的clone方法,并调用Object的 clone方法(见下面Object#clone的定义),重写后的方法应为public 的。For example(标准写法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class CloneClass implements Cloneable{
 
 public int aInt;
 
//重写clone方法
 
 public Object clone(){
 
  CloneClass o = null;
 
  try{
 
   o = (CloneClass)super.clone();
 
  }catch(CloneNotSupportedException e){
 
   e.printStackTrace();
 
  }
 
  return o;
 
 }
 

protected native Object clone() throws CloneNotSupportedException(以下源引JavaTM 2 Platform Standard Ed. 5.0 API DOC)

创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。一般来说,对于任何对象 x,如果表达式: 

x.clone() != x是正确的,则表达式: x.clone().getClass() == x.getClass()将为 true,但这些不是绝对条件。

一般情况下是: x.clone().equals(x)将为 true,但这不是绝对条件。 

按照惯例,返回的对象应该通过调用 super.clone  获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。 

按照惯例,此方法返回的对象应该独立于该对象(正被克隆的对象)。要获得 此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被克隆对象的内部“深层结构”的所有可变对象,并使用对副本的引用替 换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。 

Object 类的 clone 方法执行特定的克隆操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意:所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内 容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。 

Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常 。

解读:Object中的clone方法为 native,这也解释了上面提到的“高效”。实现Cloneable接口的类通过super.clone()调用来实现克隆能力(标准写法)。上文提到 克隆是按属性字段复制的,如果对象的属性值为可变的引用(不可变:如基本类型,final类型的,可变:如对象的引用,数组引用),那原对象跟克隆后的对 象将无法保持独立,因为他们的某个属性共同引用了一个对象,这就是“浅表复制”,这不是我们想要的,正常我们需要的是“深层复制 ”,即对对象的属性进行进一步的clone,for example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class A implements Cloneable {
    public String a[];
    public A(){
        a=new String[2];
    }
 
    public Object clone() {
        A o = null;
        try {
            o = (A) super.clone();
 o.a=(String[])a.clone();//属性a的克隆,实现A类的深度克隆
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }
}

  

如果把public String a[];改为public B a[],如果我们想要得到彻底的拷贝,需要类B也要实现Cloneable接口,特别在遇到复杂类型时,比如Vector等,要注意容器中的对象,至于您 是否需要深度复制以及复制多少层,都是根据具体需要来定的。

关联知识

Java修饰符访问权限一览

T1:修饰符的访问权限

this和super用法 

this关键字代表对象自身,在程序中主要的使用用途有以下几个方面:

l  使用this关键字引用成员变量

l  使用this关键字在自身构造方法内部引用其它构造方法

l  使用this关键字代表自身类的对象

l  使用this关键字引用成员方法

super关键字,使用super关键字可以在子类中引用父类中的内容。主要的使用形式有以下几种:

l  在子类的构造方法内部引用父类的构造方法

l  在子类中调用父类中的成员方法

l  在子类中调用父类中的成员变量

Java中的克隆(CLONE)的更多相关文章

  1. Java中如何克隆集合——ArrayList和HashSet深拷贝

    编程人员经常误用各个集合类提供的拷贝构造函数作为克隆List,Set,ArrayList,HashSet或者其他集合实现的方法.需要记住的是,Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝,这意味 ...

  2. Java实例 Part6:Java中的克隆

    目录 Part6:Java中的克隆 Example01:Java对象的假克隆 Example02:Java对象的浅克隆 Example03:Java对象的深克隆 Example04:序列化与对象克隆 ...

  3. Java 中如何使用clone()方法克隆对象?

    java为什么要 对象克隆: 在程序开发时,有时可能会遇到以下情况:已经存在一个对象A,现在需要一个与A对象完全相同的B 对象,并对B 对象的属性值进行修改,但是A 对象原有的属性值不能改变.这时,如 ...

  4. Java中深度克隆和浅度克隆

    一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中 ...

  5. 谈谈java中对象的深拷贝与浅拷贝

    知识点:java中关于Object.clone方法,对象的深拷贝与浅拷贝 引言: 在一些场景中,我们需要获取到一个对象的拷贝,这时候就可以用java中的Object.clone方法进行对象的复制,得到 ...

  6. 深入浅出Java中的clone克隆方法,写得太棒了!

    作者:张纪刚 blog.csdn.net/zhangjg_blog/article/details/18369201/ Java中对象的创建 clone 顾名思义就是 复制 , 在Java语言中, c ...

  7. 详解Java中的clone方法:原型模式

    转:http://developer.51cto.com/art/201506/478985.htm clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的 ...

  8. 分析java中clone()方法 (转载+修改)

    Java中的clone() 方法 java所有的类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制. protected native Object c ...

  9. java中传值及引伸深度克隆的思考(说白了Java只能传递对象指针)

    java中传值及引伸深度克隆的思考 大家都知道java中没有指针.难道java真的没有指针吗?句柄是什么?变量地址在哪里?没有地址的话简直不可想象! java中内存的分配方式有两种,一种是在堆中分配, ...

随机推荐

  1. struts2,hibernate,spring整合笔记(3)

    struts2,hibernate,spring整合笔记(1) struts2,hibernate,spring整合笔记(2) 配好struts和hibernate就要开始spring了 老规矩,还是 ...

  2. pen: Local Testing

    [踩点] * OLEViewer:查看 ActiveX 组件信息 [Fuzz] * Tools in This Article * COMRaider:ActiveX/ocx [utils] * Fi ...

  3. 刚接触js感觉好吃力啊

    我是一个新手,最近刚刚开始学习js这门语言,感觉好难,有一种无从下手的感觉,不知道应该从哪里学习,虽然也看了很多的书,但是对于一个没有计算机基础的人来说,真的是一种煎熬,每一个名词都要去查.万事开头难 ...

  4. python运行时间计算之timeit

    timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000) stmt:statement ...

  5. python 下的数据结构与算法---8:哈希一下【dict与set的实现】

    少年,不知道你好记不记得第三篇文章讲python内建数据结构的方法及其时间复杂度时里面关于dict与set的时间复杂度[为何访问元素为O(1)]原理我说后面讲吗?其实就是这篇文章讲啦. 目录: 一:H ...

  6. 在C#中internal关键字是什么意思?和protected internal区别

    我来补充一下,对于一些大型的项目,通常由很多个DLL文件组成,引用了这些DLL,就能访问DLL里面的类和类里面的方法.比如,你写了一个记录日志的DLL,任何项目只要引用此DLL就能实现记录日志的功能, ...

  7. jquery中的this 到底是什么意思? $(this)

    如果你学过面向对象语言的话,例如JAVA,你应该明白这个this在JAVA里的意思,简单的说,谁在调用它,它就代表文谁. 那么,用到这个jquery里,也算是蛮简单的.举两个例子,一个是单个对象,一个 ...

  8. xxx is not in the sudoers file. This incident will be reported的解决方法

    1>.进入超级用户模式.也就是输入"su -",系统会让你输入超级用户密码,输入密码后就进入了超级用户模式.(当然,你也可以直接用root用户登录,因为红旗安装过后默认的登录 ...

  9. [linux常用命令]查看当前文件夹或该文件夹下文件(夹)的大小

    du -sh  *(星号表示当前所有文件夹)可以查看当前目录下各个文件夹的大小,-s表示只显示当前文件夹(不加-s你可以看到所有文件夹下的子文件夹的大小,太多了),-h表示以合适的大小查看.(可以用- ...

  10. [php基础]Mysql日期函数:日期时间格式转换函数详解

    在PHP网站开发中,Mysql数据库设计中日期时间字段必不可少,由于Mysql日期函数输出的日期格式与PHP日期函数之间的日期格式兼容性不够,这就需要根据网站实际情况使用Mysql或PHP日期转换函数 ...