文档章节

super.clone()做了什么

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:00
字数 956
阅读 2
收藏 0

java对象如果想被克隆,它对应的类需要implements标志接口Cloneable。如果不重写clone()方法,则在调用clone()方法实现的是浅复制(所有的引用对象保持不变,意思是如果原型里这些对象发生改变会直接影响到复制对象)。重写clone()方法,一般会先调用super.clone()进行浅复制,然后再复制那些易变对象,从而达到深复制的效果。千言万语不如代码:

public class CloneTest implements Cloneable{

    private byte[] a = {1, 2, 3, 4};
    private byte[] b = {5, 6, 7, 8};
    
    public CloneTest clone() {
        CloneTest copy = null;
        try {
            copy = (CloneTest) super.clone();
            copy.a = this.a.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return copy;
    }
    
//  习惯用上面
//  @Override
//  protected Object clone() throws CloneNotSupportedException {
//      // TODO Auto-generated method stub
//      CloneTest copy = (CloneTest) super.clone();
//      copy.a = this.a.clone();
//      return copy;
//  }
    
    public byte[] getA() {
        return this.a;
    }
    
    public byte[] getB() {
        return this.b;
    }

    public static void main(String[] args) {
        CloneTest original = new CloneTest();
        CloneTest cloned = original.clone();
        
        System.out.println("original.a == cloned.a : " + (original.getA() == cloned.getA()));
        System.out.println("cloned.a[3] = " + cloned.getA()[3]);
        
        original.getA()[3] = 9;
        System.out.println("cloned.a[3] = " + cloned.getA()[3]);
        
        System.out.println("original.b == cloned.b : " + (original.getB() == cloned.getB()));
        System.out.println("cloned.b[3] = " + cloned.getB()[3]);
        
        original.b[3] = 10;
        System.out.println("cloned.b[3] = " + cloned.getB()[3]);
    }

}
original.a == cloned.a : false
cloned.a[3] = 4
cloned.a[3] = 4
original.b == cloned.b : true
cloned.b[3] = 8
cloned.b[3] = 10

super.clone(),这个操作主要是来做一次bitwise copy( binary copy ),即浅拷贝,他会把原对象完整的拷贝过来包括其中的引用。这样会带来问题,如果里面的某个属性是个可变对象,那么原来的对象改变,克隆的对象也跟着改变。所以在调用完super.clone()后,一般还需要重新拷贝可变对象。

调用super.clone()后返回的对象满足以下:

x.clone != x
x.clone.getClass() == x.getClass()
以下摘录R大在知乎的回答:

JavaDoc这段

     * The method {@code clone} for class {@code Object} performs a
     * specific cloning operation. First, if the class of this object does
     * not implement the interface {@code Cloneable}, then a
     * {@code CloneNotSupportedException} is thrown. Note that all arrays
     * are considered to implement the interface {@code Cloneable} and that
     * the return type of the {@code clone} method of an array type {@code T[]}
     * is {@code T[]} where T is any reference or primitive type.
     * Otherwise, this method creates a new instance of the class of this
     * object and initializes all its fields with exactly the contents of
     * the corresponding fields of this object, as if by assignment; the
     * contents of the fields are not themselves cloned. Thus, this method
     * performs a "shallow copy" of this object, not a "deep copy" operation.

也就是说JavaDoc指明了Object.clone()有特殊的语义,他就是能把当前对象的整个结构完全浅拷贝一份出来。

     * By convention, the returned object should be obtained by calling
     * {@code super.clone}.  If a class and all of its superclasses (except
     * {@code Object}) obey this convention, it will be the case that
     * {@code x.clone().getClass() == x.getClass()}.

每层clone()都顺着 super.clone() 的链向上调用的话最终就会来到Object.clone() ,于是根据上述的特殊语义就可以有 x.clone.getClass() == x.getClass() 。

至于如何实现的,可以把JVM原生实现的Object.clone()的语义想象成拿到this引用后通过反射去找到该对象实例的所有字段,然后逐一字段拷贝。

HotSpot vm中,Object.clone()在不同的优化层级上有不同的实现。在其中最不优化的版本是这样做的:拿到this引用,通过对象头里记录的Klass信息去找出这个对象有多大,然后直接分配一个新的同样大的空对象并且把Klass信息塞进对象头(这样就已经实现了x.clone.getClass() == x.getClass()这部分语义),然后直接把对象体 的内容看作数组拷贝一样从源对象“盲”拷贝到目标对象,bitwise copy。然后就完事啦。

-----------------------------------------------------------------------------------

我的理解是super.clone() 的调用就是沿着继承树不断网上递归调用直到Object 的clone方法,而跟据JavaDoc所说Object.clone()根据当前对象的类型创建一个新的同类型的空对象,然后把当前对象的字段的值逐个拷贝到新对象上,然后返回给上一层clone() 调用。
也就是说super.clone() 的浅复制效果是通过Object.clone()实现的。

本文转载自:http://www.jianshu.com/p/6ee09071f74d

上一篇: 优先队列
AllenOR灵感
粉丝 11
博文 2635
码字总数 83001
作品 0
程序员
私信 提问
Effective Java 第三版——13. 谨慎地重写 clone 方法

Tips 《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8...

M104
2018/01/04
0
0
Cloneable Interface in java

一个类实现该接口表明该类的实例通过java.lang.Object#clone()方法拷贝字段的字段是合法的。 在一个没有实现该接口的实例上调用对象的clone方法会抛出CloneNotSupportedException异常。 通常...

Rksi5
2014/04/24
176
0
Java中对象的浅拷贝与深拷贝

Java中的拷贝方式分为深拷贝和浅拷贝。简单来说,深拷贝就是把一个对象中的所有值,如果被拷贝对象中有对其他对象的引用,那么这个引用指向的对象本身会被重新创建。浅拷贝和深拷贝类似,但是...

夜默
2013/06/18
102
0
JAVA深复制(深克隆)与浅复制(浅克隆)

1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不 复制...

MZHS
2013/07/22
152
4
JAVA深复制(深克隆)与浅复制(浅克隆)

1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不 复制...

苏叶晚晚
2013/02/17
210
0

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
6
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部