What does super.clone() do?

翻译自:https://www.pixelstech.net/article/1420629927-What-does-super-clone%28%29-do


Object 类中声明了一个受保护的方法

protected native Object clone() throws CloneNotSupportedException;

它的作用是:使所有类在需要的时候可以对自己进行克隆。
当需要一个类的新实例同时保持与原始对象相同的状态(实例属性),通常使用 clone 方法。任何想要实现克隆的类都必须实现标记接口(marker interface) Cloneable 。

如果实现 Cloneable 接口的类没有覆盖 Object.clone() 方法,则将调用 Object.clone() 方法来创建原始对象的二进制副本,该副本相当于一个浅拷贝,其中包含所有引用的对象保持不变。 这意味着在原始对象中包括私有引用的所有引用都将被复制到克隆对象。 Object.clone() 是一个本地(native)方法,它实现浅拷贝。 有关更多信息,请参阅 Object.clone() source code

如果一个实现 Cloneable 接口的类覆盖了 Object.clone() 方法,通常会首先调用 super.clone() 来创建原始对象的二进制拷贝,然后根据二进制拷贝相应地执行深拷贝。
看下面的例子:

public class CloneTest implements Cloneable {
    private byte[] a = {1, 2, 3, 4, 5};
    private byte[] b = {5, 4, 3, 2, 1};

    public CloneTest clone(){
        CloneTest that = null;
        try{
            that = (CloneTest)super.clone();        //Make a binary copy
            that.b = this.b.clone();                //Do customized operation
            return that;
        } catch (CloneNotSupportedException ex){
            ex.printStackTrace();
        }
        return that;
    }

    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();

        //About original.a
        System.out.println("original.a == cloned.a : " + (original.getA() == cloned.getA()));
        System.out.println("cloned.a[2] = " + cloned.getA()[2]);
        //Modify original.a[2]
        original.getA()[2] = 10;
        System.out.println("cloned.a[2] = " + cloned.getA()[2]);

        //About original.b
        System.out.println("original.b == cloned.b : " + (original.getB() == cloned.getB()));
        System.out.println("cloned.b[2] = " + cloned.getB()[2]);
        //Modify original.b[2]
        original.getB()[2] = 10;
        System.out.println("cloned.b[2] = " + cloned.getB()[2]);
    }
}

输出:

original.a == cloned.a : true
cloned.a[2] = 3
cloned.a[2] = 10
original.b == cloned.b : false
cloned.b[2] = 3
cloned.b[2] = 3

你对 super.clone() 方法感到困惑吗?
为什么 super.clone() 可以转换成 CloneTest ?
通常 super 意味着父类,这意味着我们只会得到一个超类实例的副本,对吧?
那么这个对象就会被强制转换为不该正确的对象上,对吧?

The fact is that the super.clone() will return an object that calls the super.clone() method.

事实是, super.clone() 将返回一个调用 super.clone() 方法的对象。

要理解为什么,请仔细阅读有关 Object.clone() 方法的内容。
Object中的clone() 的实现检查实际类是否实现 Cloneable 接口,并创建该实际类的实例。
这意味着下面的关系应该是正确的:

x.clone() != x
x.clone().getClass() == x.getClass()

关于 clone() 方法的另一个重要注意事项是,在覆盖 clone() 方法时,应该显式克隆任何可变对象。
上面的例子有一个会导致问题的错误。
可变对象数组 a 没有被显式克隆,因此克隆对象将与原始对象共享相同的数组引用。如果数组a中的元素发生更改,则此更改也将反映在克隆的对象上。

程序执行的结果:

D:\N3verL4nd\Desktop>javac CloneTest.java
D:\N3verL4nd\Desktop>java CloneTest
original.a == cloned.a : true
cloned.a[2] = 3
cloned.a[2] = 10
original.b == cloned.b : false
cloned.b[2] = 3
cloned.b[2] = 3

从输出中,original.a == cloned.a:true 意味着数组 a 的引用在原始和克隆对象中是相同的。 所以 cloned.a[2] 更改为10。

为了解决这个问题,需要在 clone 方法中添加 that.a = this.a.clone();

关于使用 clone() 的一个常规提示是在重写 clone() 方法时要特别小心。检查类中的每个可变对象,看看是否需要对其进行深拷贝。 尽可能不要使用 clone() 方法。


总结:
1) super.clone() 将返回一个调用 super.clone() 方法的对象。
2) clone 方法需要满足的语义:

x.clone() != x
x.clone().getClass() == x.getClass()

3) Cloneable 仅仅是一个标记接口(marker interface)

public interface Cloneable {
}

import org.junit.Test;

class Father {
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Son extends Father implements Cloneable {
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Test4 {

    @Test
    public void test2() throws CloneNotSupportedException {
        Son son = new Son();
        System.out.println(son.clone());
    }

    @Test
    public void test3() throws CloneNotSupportedException {
        Father son = new Son();
        System.out.println(son.clone());
    }
}

clone方法也是一个虚方法,想要实现这种对象的拷贝操作,最终实现都是 Object.clone。

https://www.zhihu.com/question/63667745

https://www.zhihu.com/question/52490586/answer/130786763

http://wangwengcn.iteye.com/blog/1622195

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值