1、案例
对于上文中的克隆方法加以改进:
原型类:
public class Student implements Cloneable {
private String name;
public Student(String name) {
System.out.println("原型对象创建成功!!!");
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{'name' = " + name + "}, " +
"hashCode = " + this.hashCode();
}
//实现对象克隆
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("克隆成功!!!");
return super.clone();
}
}
测试:
@Test
public void test1() throws CloneNotSupportedException {
Student newStudent = new Student("张三");
Student cloneStudent = (Student) newStudent.clone();
System.out.println("原型对象: " + newStudent);
System.out.println("克隆对象: " + cloneStudent);
}
2、引用数据类型
-
上述案例中我们可以看出克隆是克隆成功了,并且没有走构造方法,所克隆出的对象地址和原对象地址不一样,是新的对象;
-
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象;
-
但是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,并没有
new
一个新的对象,而是进行引用传递指向原有的引用; -
在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
我们添加原型类的成员变量:
School:
public class School {
private String name;
public School(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Student:
public class Student implements Cloneable {
private String name;
private School school;
public Student(String name, School school) {
this.name = name;
this.school = school;
}
public void setName(String name) {
this.name = name;
}
public School getSchool() {
return school;
}
@Override
public String toString() {
return "Student{'name' = " + name + ", 'school' = " + school.getName() + "}, " +
"Student.hashCode = " + this.hashCode() + ", " +
"name.hashCode" + name.hashCode() + ", " +
"School.hashCode = " + school.hashCode();
}
//实现对象克隆
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试:
@Test
public void test2() throws CloneNotSupportedException {
Student newStudent = new Student("张三", new School("清华"));
Student cloneStudent = (Student) newStudent.clone();
System.out.println("原型对象:" + newStudent);
System.out.println("克隆对象:" + cloneStudent);
System.out.println("=====================修改克隆对象信息========================");
cloneStudent.setName("李四");
cloneStudent.getSchool().setName("北大");
System.out.println("修改后的原型对象:" + newStudent);
System.out.println("修改后的克隆对象:" + cloneStudent);
}
上述案例可以看出:
- 克隆确实产生新的对象,但是引用数据类型只是进行了引用传递;
- 以至于我们修改了cloneStudent的学校,newStudent也随之修改了;
- 那为什么String也是引用数据类型,cloneStudent的那么由“张三”改为“李四”,而newStudent没有呢,那是因为String不可变,传入新的,当然指向新的地址了。