美文网首页
super.clone()做了什么

super.clone()做了什么

作者: 囧囧有神2号 | 来源:发表于2017-09-03 13:30 被阅读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()实现的。

    相关文章

      网友评论

          本文标题:super.clone()做了什么

          本文链接:https://www.haomeiwen.com/subject/jdbdjxtx.html