Java&&Clone之浅拷贝和深拷贝

时间:2021-01-18 19:53:44

1.Object类中有clone方法,但是Object又没有实现Cloneable接口,这是为什么?对于一个没有实现cloneable的类来说,还可以用从Object类继承而来的clone方法实现一些基本的值的复制操作,那是不是可以说clone方法并没有对对象是否属于Cloneable类型进行检验?

Object类的clone是protected的( protected Object clone () throws CloneNotSupportedException),不能直接调用,可以被子类调用。Object类的clone会知道对象大小,为它分配足够的内存空间,并将旧对象的内容复制到新的对象中。但是Object.clone()执行其动作之前必须先检查class是否实现了Cloneable接口。
Cloneable接口是一个标记接口,也就是没有任何内容,定义如下。
package java.lang;
public interface Cloneable{
}
这里分析一下这接口的用法。
java中clone的含义是,假设X是一个非空对象,则:
1.x.clone() != x 为true,就是说它们不是同一个对象;
2.x.clone().getClass() == x.getClass()为true,说明它们是同一个类型class;
3.x.equals(x.clone())为true,说明逻辑上应当相当。

clone方法是在Object中定义的,而且是protected类型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出   CloneNotSupportedException
Object中默认的实现是一个浅复制,也就是表面复制,如果需要实现深层次的复制,必须对类中可变域生成新的实例。
public class Unsupported{
	public Object clone(){
		Object obj;
		try{
			obj = supper.clone();
		}catch(CloneNotSupportedException ex){
			ex.printStackTrace();
		}
		return obj;
	}
}
加上implements Cloneable就可以了。当然也可以不实现这个接口,但是覆盖clone方法,其代码如下:
public class Unnormal{
	public Object clone(){
		return new Unnormal();
	}
}
这样肯定没问题的,不过已经和java中的clone机制没有关系了。
下面举一个例子说明浅复制和深复制。
public class ShallowCopy implements Cloneable{
	private Date begin;
	public Date getBegin(){return this.begin;}
	public void setBegin(Date d){this.begin=d;}
	public Object clone(){
		Object obj = null;
		try{
			obj=super.clone();
		}catch(CloneNotSupportedException ex){
			ex.printStackTrace();
		}
		return obj;
	}
}

public class DeepCopy implements Cloneable{
	private Date begin;
	public Date getBegin(){return this.begin;}
	public void setBegin(Date d){this.begin=d;}
	public Object clone(){
		DeepCopy obj = null;
		try{
			obj = (DeepCopy)super.clone();
		}catch(CloneNotSupportedException ex){
			ex.printStackTrace();
		}
		obj.setBegin((Date)this.getBegin().clone());
		return obj;
	}
}

总结:
clone方法是在Object中定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportException。说clone方法并没有对对象是否属于cloneable类型进行检查这个观点是不正确的。因为cloneable接口的出现跟接口的正常使用没有任何关系,特别是它并不指定clone方法--------该方法从object类中继承而来,该接口只是作为一个标记。这句话通俗的说就是以下3点:首先,clone方法是Object类的一个方法,所以任何类都会自动拥有这一个方法。其次,这并不说明该类就可以调用clone了,因为Javac或者java需要程序员显示地指明该类可以调用clone,方法就是写上这个字符串”implements Cloneable“。再次,这个字符串只是起一个指示作用,没有其他功能,这是javac或者java的规定。