当你将一个对象的引用作为参数传到一个方法中,而这个方法可能会改变该引用所指对象的属性,但你不想让这种事情发生,此时java的克隆技术能帮到你。下面就来讨论一下,如何让你的类具有可克隆的能力,怎样才能做到深层拷贝。
虽然Object类定义了clone()方法,但并不是每个class天生都具有克隆能力,要想使你的类具有克隆能力,有三件事儿你必须要做:
1、实现Cloneable接口。
2、覆盖clone()方法,并把其访问属性改为public的,否则只能在同包中的类或子类中访问,因为Object的clone()方法是protected的。
3、在clone()方法中调用super.clone()方法。
package scjp.cloning;
public class Cloing02 {
public static void main(String[] args) {
MyObject obj1 = new MyObject("eric",24);
MyObject obj2 = null;
try {
obj2 = (MyObject)obj1.clone();//obj2是obj1的克隆,此时它们的内容一样,但它们是两个独立的对象。
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
//对obj2对象属性的更改不会影响到obj1
obj2.setAge(25);
obj2.setName("lth");
System.out.println(obj1.getName()); //eric
System.out.println(obj1.getAge()); //24
System.out.println(obj2.getName()); //lth
System.out.println(obj2.getAge()); //25
}
}
class MySuperObject{
String name;
public MySuperObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//1、实现Cloneable接口
class MyObject extends MySuperObject implements Cloneable{
int age;
public MyObject(String name,int age) {
super(name);
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//2、覆盖clone()方法。
//如果没有实现Cloneable接口的话,clone()方法会抛出CloneNotSupportedException异常。
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone(); //3、调用super.clone()
}
}
深层拷贝
上面的例子可以看出,被克隆的类的属性都属于基本类型,所以牵涉不到深层拷贝的问题。但如果被克隆的类是一个组合类(其它类的对象作为成员属性)再用上面的方法就只能做到浅层拷贝即对象成员仍指向本体的对象成员。要想做到深层拷贝需在覆盖clone()方法时下点工夫。
package scjp.cloning; public class Cloning03 { public static void main(String[] args) { ClassRoom classRoom = new ClassRoom(); ClassRoom classRoom2 = null; try { classRoom2 = (ClassRoom)classRoom.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } //更改classRoom2对象的成员属性,不会对classRoom造成影响。 classRoom2.teacher.name = "Tom"; for(int i = 0;i < classRoom2.students.length;i++){ classRoom2.students[i].name = "stu"+i; classRoom2.desks[i].hight = 300; classRoom2.desks[i].width = 400; } System.out.println(classRoom); System.out.println(classRoom2); } } class Student implements Cloneable{ String name; public Student(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Teacher implements Cloneable{ String name; public Teacher(String name) { this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Desk implements Cloneable{ int hight; int width; public Desk(int hight,int width) { this.hight = hight; this.width = width; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class ClassRoom implements Cloneable{ //每个成员都要实现Cloneable接口。 Teacher teacher; Student[] students; Desk[] desks; public ClassRoom() { this.teacher = new Teacher("Eric"); this.students = new Student[10]; this.desks = new Desk[10]; for(int i = 0;i < this.students.length;i++){ this.students[i] = new Student("student"+i); this.desks[i] = new Desk(200,300); } } @Override protected Object clone() throws CloneNotSupportedException { ClassRoom classRoom = null; classRoom = (ClassRoom)super.clone(); //每一个成员都要克隆 classRoom.teacher = (Teacher)classRoom.teacher.clone(); classRoom.students = classRoom.students.clone(); classRoom.desks = classRoom.desks.clone(); //集合中的每一个对象也都要克隆 for(int i = 0;i < classRoom.students.length;i++){ classRoom.students[i] = (Student)classRoom.students[i].clone(); classRoom.desks[i] = (Desk)classRoom.desks[i].clone(); } return classRoom; } @Override public String toString() { StringBuilder sbBuilder = new StringBuilder(); sbBuilder.append("Teacher:").append(this.teacher.name).append("\r\n"); sbBuilder.append("Students:"); for(int i = 0;i < this.students.length;i++){ sbBuilder.append(students[i].name); sbBuilder.append(","); } sbBuilder.append("\r\n"); sbBuilder.append("Desk(Hight,Width):"); for(int i = 0;i < this.students.length;i++){ sbBuilder.append("("); sbBuilder.append(desks[i].hight); sbBuilder.append(",").append(desks[i].width).append(")"); } sbBuilder.append("\r\n"); return sbBuilder.toString(); } }
Teacher:Eric Students:student0,student1,student2,student3,student4,student5,student6,student7,student8,student9, Desk(Hight,Width):(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300)(200,300) Teacher:Tom Students:stu0,stu1,stu2,stu3,stu4,stu5,stu6,stu7,stu8,stu9, Desk(Hight,Width):(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)(300,400)
继承体系中的克隆
默认情况下你自己写的类是不具有克隆能力的,但当你做完了文章开始时所说的三件事后,你的类便拥有了克隆能力,并且继承自该类的所有子类也都与生具有克隆能力。