Java设计模式 —— 【创建型模式】原型模式(浅拷贝、深拷贝)详解-一、浅拷贝

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不可变,传入新的,当然指向新的地址了。

上一篇:关于BeanUtils.copyProperties是否能正常复制字段【详细版】


下一篇:VBA数据库解决方案第十七讲:Recordset对象记录位置的定位方法