翻译自: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