What does super.clone() do?

  Pi Ke        2015-01-07 05:25:52       31,409        0          English  简体中文  Tiếng Việt 

Object 类有一个受保护的 clone() 方法声明,以便所有类在需要时都可以克隆自身。当需要类的新的实例,同时又需要保持与原始对象相同的状态时,通常使用 clone()。任何想要启用克隆的类都必须实现标记接口 Cloneable。

如果实现 Cloneable 的类没有重写 Object.clone() 方法,则将调用 Object.clone() 方法来只创建一个原始对象的二进制副本,这相当于一个克隆,其中所有引用的对象保持不变。这意味着原始对象中的所有引用(包括私有引用)都将被复制到克隆对象中。Object.clone() 是一个本地方法,它执行浅复制。更多信息,请参见 Object.clone() 源代码

如果实现 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();		//创建二进制副本
			that.b = this.b.clone();				//执行自定义操作
			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();
		
		//关于 original.a
		System.out.println("original.a == cloned.a : " + (original.getA() == cloned.getA()));
		System.out.println("cloned.a[2] = " + cloned.getA()[2]);
		//修改 original.a[2]
		original.getA()[2] = 10;
		System.out.println("cloned.a[2] = " + cloned.getA()[2]);
		
		//关于 original.b
		System.out.println("original.b == cloned.b : " + (original.getB() == cloned.getB()));
		System.out.println("cloned.b[2] = " + cloned.getB()[2]);
		//修改 original.b[2]
		original.getB()[2] = 10;
		System.out.println("cloned.b[2] = " + cloned.getB()[2]);
	}
}

你是否对 super.clone() 方法感到困惑?为什么 super.clone() 可以转换为 CloneTest?通常 super 表示父类,这意味着我们只会得到父类实例的副本,对吗?然后对象被向下转换为对象,这应该是不正确的,对吗?事实上,super.clone() 将返回调用 super.clone() 方法的对象。要理解原因,请仔细阅读 Object.clone() 方法的作用。Objectclone() 的实现会检查实际类是否实现了 Cloneable,并创建该实际类的实例。这意味着下面的关系应该是正确的:

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

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

程序执行的结果显示了这种确切的行为:

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(0 方法中添加 that.a = this.a.clone();。

关于使用 clone() 的一个一般性提示是在重写 clone() 方法时要格外小心。检查类中的每个可变对象,并查看是否需要对其进行深度复制。尽可能不要使用 clone()。

CLONEABLE  SUPER.CLONE()  CLONE  JAVA 

       

  RELATED


  0 COMMENT


No comment for this article.



  RANDOM FUN

Hey, you!