Java 提供了一个 protected 修饰的 clone()方法,该方法用于帮助其他对象来实现"自我克隆",也就是得到一个当前对象的副本。由于 Object 类提供的clone()方法使用了 protected 修饰,因此该方法只能被子类重写或调用。
自定义类实现"克隆"的步骤如下。
- 自定义类实现 Cloneable 接口。这是一个标记性的接口,实现该接口的对象可以实现"自我克隆",该接口里没有定义任何方法。
注意:如果不实现此接口,那么会抛出异常
java.lang.CloneNotSupportedException
- 自定义类实现自己的 clone()方法。
- 实现 clone()方法时通过 **super.clone() ;**调用 Object 实现的 clone() 方法来得到该对象的副本,并返回该副本。
下面先简单介绍下两种克隆的区别:
浅拷贝:引用变量拷贝的是地址,所有克隆的对象改变了对象的属性, 原对象的属性也发生改变
深拷贝:引用变量拷贝一份对象,克隆对象的属性改变,原对象的属性不发生变化
如下程序示范了如何实现"自我克隆"。
public class Professor **implements Cloneable**{
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*
**public Object clone() throws CloneNotSupportedException {
return super.clone();**
}*/
}
// 实现 Cloneable 接口
public class Student implements Cloneable{
private int age;
Professor p;
public Professor getP() {
return p;
}
public void setP(Professor p) {
this.p = p;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//通过调用 super.clone ()来实现 clone ()方法
public Object clone() throws CloneNotSupportedException {
Student stu=(Student) super.clone();
//深拷贝
//stu.p = (Professor)this.p.clone();//克隆professor对象
return stu;
//return super.clone();//调用object 的clone方法
}
}
/**
* 定义一个student类,创建一个对象,clone克隆对象
* 1.自定义的类,使用clone 方法,当前类必须要实现Cloneable接口
* 如果不实现此接口,那么会抛出异常java.lang.CloneNotSupportedException
* 2.因为object类的clone是protected修饰的,要重写此方法
* 才能在不同包中访问,把访问修饰符定义为public
* 3.Cloneable接口中没有方法,是一个标识性的接口,
* 针对Object类的clone方法的实现
* 4.浅拷贝:引用变量拷贝的是地址,所有克隆的对象改变了对象的属性,
* 原对象的属性也发生改变
* 5.深拷贝:引用变量拷贝一份对象,克隆对象的属性改变,原对象的属性不发生变化
*
*/
public class TestClone {
public static void main(String[] args) throws CloneNotSupportedException {
Student stu1=new Student();
stu1.setAge(10);
System.out.println(stu1.getAge());
Professor p=new Professor();
p.setAge(22);
stu1.setP(p);
// clone 得到 stu1 对象的副本
Student stu2=(Student) stu1.clone();
stu2.setAge(18);
System.out.println(stu2.getAge());
stu2.getP().setAge(30);
System.out.println(stu1.getP().getAge());
System.out.println(stu2.getP().getAge());
}
}
上面程序让 Student 类实现了 Cloneable 接口 而且实现了 clone() 方法,因此 Student 对象就可实现"自我克隆" 一一克隆出来的对象只是原有对象的副本。
Object 类提供的 clone 机制只对对象里各实例变量进行"简单复制",如果实例变量类型是引用类型,Object 的 Clone机制也只是简单复制这个引用变量,这样原有对象的引用类型的实例变量与克隆对象的引用类型的实例变量依然指向内存中的同一个实例(浅拷贝/浅克隆),所以上面程序在最后两行代码处输出结果相同。上面程序"浅克隆"出来的 stu1、stu2所指向的对象在内存中的存储示意图如图1所示。
需要指出的是, Object 类的 clone()方法虽然简单易用, 但它只是一种"浅克隆"一一它只克隆该对象的所有成员变量值 ,不会对引用类型的成员变量值所引用的对象进行克隆。如果开发者需要对对象进行"深克隆",则需要开发者自己进行"递归"克隆,保证所有引用类型的成员变量值所引用的对象都被复制了。上面程序"深克隆"出来的 stu1、stu2所指向的对象在内存中的存储示意图如图所示。