克隆,即复制一个对象。日常编程中,我们常常需要对一个对象进行复制然后操作,普通的做法就是new出一个对象,一个个赋值;如果对象属性偏多,编写的代码则很臃肿;
在java中,Object类中实现了clone方法,用于克隆对象。
在java中克隆主要为浅克隆和深克隆;
实现克隆的方式主要是以下几个步骤
浅克隆:复制对象时仅仅复制对象本身,包括基本属性,但该对象的属性引用其他对象时,该引用对象不会被复制,即拷贝出来的对象与被拷贝出来的对象中的属性引用的对象是同一个。
深克隆:复制对象本身的同时,也复制对象包含的引用指向的对象,即修改被克隆对象的任何属性都不会影响到克隆出来的对象。
文字的表述有时很饶人,直接来代码体现吧;
public class Student implements Cloneable{
private int num;
private String name;
public Student() {
}
public Student(int num, String name) {
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类:
public static void main(String[] args) throws CloneNotSupportedException {
Student a = new Student(1,"tom");
Student b = (Student) a.clone();
b.setNum(2);
b.setName("david");
System.out.println(a.toString());
System.out.println(b.toString());
}
测试结果:
由测试结果可以看出:
创建a学生,a学生克隆到b学生。
然后修改b学生的值,他们的值是互相不影响的。
接下来我们来看看,在对象内有属性不是基本类型的时候;
// 修改后的学生类,加入了新的属性Achievement对象
public class Student implements Cloneable{
private int num;
private String name;
private Achievement achievement;
public Student() {
}
public Student(int num, String name, Achievement achievement) {
this.num = num;
this.name = name;
this.achievement = achievement;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Achievement getAchievement() {
return achievement;
}
public void setAchievement(Achievement achievement) {
this.achievement = achievement;
}
@Override
public String toString() {
return "Student{" +
"num=" + num +
", name='" + name + '\'' +
", achievement=" + achievement +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// Achievement成绩类
public class Achievement implements Cloneable{
private float math;
private float english;
public Achievement() {
}
public Achievement(float math, float english) {
this.math = math;
this.english = english;
}
public float getMath() {
return math;
}
public void setMath(float math) {
this.math = math;
}
public float getEnglish() {
return english;
}
public void setEnglish(float english) {
this.english = english;
}
@Override
public String toString() {
return "Achievement{" +
"math=" + math +
", english=" + english +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试类:
public class test {
public static void main(String[] args) throws CloneNotSupportedException {
Achievement achievement = new Achievement(60,90);
Student a = new Student(1,"tom",achievement);
Student b = (Student) a.clone();
b.setNum(2);
b.setName("david");
System.out.println(a.toString());
System.out.println(b.toString());
// 修改b学生属性achievement的值
b.getAchievement().setMath(70);
b.getAchievement().setEnglish(40);
System.out.println("修改后~~~~");
System.out.println(a.toString());
System.out.println(b.toString());
}
}
测试结果:
由结果我们可以很清晰的看出:
修改b学生achievement属性的值,两个对象的achievement属性的值都会改变,这就是浅克隆;
继续我们直接上代码:
public class Student implements Cloneable{
private int num;
private String name;
private Achievement achievement;
// get set .......
// 主要是修改克隆方法中逻辑
// 对象仍然正常赋值,然而属性achievement使用当前对象的Achievement对象的clone方法进行克隆;
@Override
public Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.achievement = (Achievement) this.getAchievement().clone();
return student;
}
}
测试类:(和之前一样)
public class test {
public static void main(String[] args) throws CloneNotSupportedException {
Achievement achievement = new Achievement(60,90);
Student a = new Student(1,"tom",achievement);
Student b = (Student) a.clone();
b.setNum(2);
b.setName("david");
System.out.println(a.toString());
System.out.println(b.toString());
b.getAchievement().setMath(70);
b.getAchievement().setEnglish(40);
System.out.println("修改后~~~~");
System.out.println(a.toString());
System.out.println(b.toString());
}
}
测试结果:
由测试结果我们可以看出,num为1的学生和num为2的学生的成绩都不一样了,这样我们就完成了深克隆的操作。
我们使用一组图来清晰的表示一下:
这样就是一个简单的java克隆(浅克隆和深克隆)的理解。
参考资料:
深入理解Java的浅克隆与深克隆