目录
Object基类中声明了一个clone()方法,用于实现对象的拷贝。在Java中,所有对象都是Object的子类,因此,都可以通过clone()方法创建新的类型实例。但是Object类中的clone()方法声明为protected,不能直接调用。子类要调用Object类中的clone()方法通常是重写clone()方法,并在重写方法中通过super.clone()进行调用。
Object类中clone()方法的声明:
/** Creates and returns a copy of this object. The precise meaning
* of "copy" may depend on the class of the object.
/
protected native Object clone() throws CloneNotSupportedException;
一、clone的条件
具体看下Object类中对clone()方法的行为描述:
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.
某个类型要实现clone功能,必须实现Cloneable接口,否则将会抛出CloneNotSupportedException。
二、浅拷贝和深拷贝
我们直到,Java中的类型分为基本类型和引用类型,浅拷贝和深拷贝的区别在于对于引用类型的赋值方式不同。对于基本类型,浅拷贝和深拷贝都是值传递;对于引用类型,浅拷贝是传址,深拷贝则是传值。
具体举例分析,假设定义了一个类型Apple,包含两个域:int类型的域id和引用类型Type域type。
Apple中重写了父类的clone()方法,现在创建一个Apple类型对象Apple apple = new Apple(1, new Type("红富士")),并且调用clone()方法创建了一个新的实例名为copy,在内存中apple和copy两个Apple实例int域与Type域的指向关系如下图所示,也就是说对于基本类型,cone()会创建一个新的副本,而引用类型,如果是浅拷贝,那么拷贝的对象中的引用只是直接指向原来的对象引用域的内存地址,不会为引用类型创建新的副本。
对于深拷贝,同样的过程,将会为拷贝对象引用类型的域也创建一份新的副本,如下图所示:
三、如何实现浅拷贝和深拷贝
从第二点分析可以看到,浅拷贝和深拷贝只是对引用类型的域赋值方式不同。对于浅拷贝,只需在重写的clone()方法中调用super.clone()返回新的对象即可,对于深拷贝则要求引用类型也重写clone()方法,并且在浅拷贝重写的clone()方法中,调用引用类型域的clone()方法并更新引用类型的域。
仍然以Apple为例:
1、浅拷贝
class Apple implements Cloneable{
int id;
Type type;
public Apple(int id, Type type) {
super();
this.id = id;
this.type = type;
}
/*浅拷贝
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone() {
return super.clone();
}
}
2、深拷贝
class Apple implements Cloneable{
int id;
Type type;
public Apple(int id, Type type) {
super();
this.id = id;
this.type = type;
}
/*深拷贝
* (non-Javadoc)
* @see java.lang.Object#clone()
*/
public Object clone() {
Apple apple = (Apple) super.clone();
apple.type = (Type) type.clone();
return apple;
}
}