- clone()方法是Object类的方法,是protected类型,同时也是native方法。
- 默认的克隆操作是“浅拷贝”,只能对对象逐个域进行拷贝,并没有克隆对象中引用的其他对象(对于子对象采用共享的方式),一般只是克隆基本数据类型。
- 浅拷贝有什么影响?
-
- 如果原对象与浅克隆对象共享的子对象是不变的,那么这种共享就是安全的。如果子对象属于不可变的类,如String;或者子对象一直包含不变的常量,没有更改器方法会改变它,也没有方法生成它的引用,这种情况下是安全的。
- 通常子对象都是可变的,必须重新定义clone方法来建立“深拷贝”,同时克隆所有的子对象。
- 对于每一个类,需要确定:
-
- 默认的clone()方法是否满足要求。
- 是否可以在可变的子对象上调用clone方法来修补默认的clone方法。
- 是否不该使用clone。
- 如果对象要调用clone方法,所属类必须:
-
- 实现Cloneable接口
- 重新定义clone方法,并指定修饰符为public。
- Cloneable接口中没有clone方法,该方法是从Object类中继承的。如果一个对象请求克隆,但是没有实现该接口,会出现异常。Cloneable接口是Java提供的标记接口(tagging interface)。标记接口不包含任何方法,唯一的作用就是在类型查询中使用instanceOf。
- 即使clone的默认(浅拷贝)能够满足要求,还是需要实现Cloneable接口,将clone()方法定义为public ,再调用super.clone()。
//默认的clone方法返回类型为Object
public CloneTest clone() throws CloneNotSupportedException{
return (CloneTest)super.clone();
}
- 要实现深拷贝,还要克隆对象中可变的实例域。
public CloneTest clone() throws CloneNotSupportedException{
CloneTest cTest=(CloneTest)super.clone();
cTest.day=(Date)day.clone();
return cTest;
}
- 如上,还要对CloneTest类中的Date day变量进行克隆,由于Date类已经实现了Cloneable接口,所以可以调用clone方法对子对象进行克隆。
- 所有的数组类型都有一个public的clone方法,可以用这个方法建立一个新数组,包含原数组的所有副本元素。
package Clone;
public class CloneArray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] original={0,1,2,3,4,5,6,7,8,9};
int[] cloned=null;
cloned=original.clone();
System.out.println("原数组元素:");
for (int i = 0; i < original.length; i++) {
System.out.print(original[i]);
}
System.out.println("\n克隆数组元素:");
for (int i = 0; i < cloned.length; i++) {
System.out.print(cloned[i]);
}
for (int i = 0; i < cloned.length; i++) {
cloned[i]=10-i;
}
System.out.println("\n原数组元素:");
for (int i = 0; i < original.length; i++) {
System.out.print(original[i]);
}
System.out.println("\n克隆数组元素:");
for (int i = 0; i < cloned.length; i++) {
System.out.print(cloned[i]);
}
}
}
- 输出如下:
原数组元素:
0123456789
克隆数组元素:
0123456789
原数组元素:
0123456789
克隆数组元素:
10987654321
- 浅拷贝实例:
package Clone;
public class CloneTest implements Cloneable {
private int a=10;
private double b=2.0;
public void setA(int a){
this.a=a;
}
public int getA(){
return this.a;
}
public void setB(double b){
this.b=b;
}
public double getB(){
return this.b;
}
public CloneTest clone() throws CloneNotSupportedException{
return (CloneTest)super.clone();
}
public static void main(String[] args) {
CloneTest cloneTest=new CloneTest();
CloneTest cloneTest2 = null;
try {
cloneTest2=cloneTest.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Clonetest.a="+cloneTest.getA()+" Clonetest.b="+cloneTest.getB());
System.out.println("Clonetest2.a="+cloneTest2.getA()+" Clonetest2.b="+cloneTest2.getB());
cloneTest2.setA(3);cloneTest2.setB(3.0);
System.out.println("Clonetest.a="+cloneTest.getA()+" Clonetest.b="+cloneTest.getB());
System.out.println("Clonetest2.a="+cloneTest2.getA()+" Clonetest2.b="+cloneTest2.getB());
}
}