浅克隆与深克隆以及实现深克隆的几种方式

欢迎各位猿哥指教批评

1、在我们的开发过程中经常遇到要复制一个对象

比如:

   @Test
    public void test1(){
        People p1 = new People("1","zhang3",12);
        People p2 = p1 ;
        System.out.println(p1==p2);// 输出  true
        p1.setUsername("li4");
        System.out.println(p2.getUsername()); // 输出 li4

    }

上面这段代码得到的结果是:

图1

将p1这个引用传给了 p2 ,   p1和p2 指向了栈中的同一个内存对象。当我们改变 p1中 username的值是 p2中的值也发生了改变。

很显然 我们要的并不是这样的结果,那么我们如何才能得到下图所示的结果呢

图2

2、浅克隆  :对象进行自我复制 ,返回一个新对象。新对象的所有变量都与自己的变量值相同,而新对象所有对其他对象的引用仍然和原对象的引用值一样。

实现浅克隆的三个步骤:

  • 实现 Cloneable 接口。
  • 重写Object类中的clone()方法 ,并声明为public 。
  • 在重写的clone()方法中调用 super.clone()  。
    @Override
    public Object clone() throws CloneNotSupportedException {
        People p = null;
        try {
            p = (People) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
         return p ;
    }
    @Test
    public void test2()throws CloneNotSupportedException{
        People p1 = new People("1","zhang3",12);
        People p2 = (People) p1.clone();
        System.out.println(p1==p2);// 输出 false
        p1.setUsername("li4");
        System.out.println(p2.getUsername()); // 输出 zhang3
    }

  如此调整之后 p1和p2就是2个不同的引用,分别指向2个不同内存空间中的对象 ,当我们对其中某一个对象变量更改的时候不会影响另一个。 前面我们说 浅克隆概念的时候还有一个特性,那就是  新对象所有对其他对象的引用仍然和原对象的引用值一样。这个是什么意思呢?请看下面这个例子:

我们首先创建一个student对象 ,并作为属性 放入 People中 

package com.wcly.activemqTest;

public class Student {

    private String classNo;
    private String teacherName ;

    public String getTeacherName() {
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }

    public String getClassNo() {
        return classNo;
    }

    public void setClassNo(String classNo) {
        this.classNo = classNo;
    }

    public Student(String classNo, String teacherName) {
        this.classNo = classNo;
        this.teacherName = teacherName;
    }
}
package com.wcly.activemqTest;

public class People implements Cloneable{

    private String id;
    private String username;
    private int age;
    private Student stu ;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    public People(String id, String username, int age,Student stu) {
        this.id = id;
        this.username = username;
        this.age = age;
        this.stu = stu ;
    }



    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if(obj instanceof People) {
            People b = (People) obj ;
            if (this.getId() == b.getId()
                    && this.getUsername().equals(b.getUsername())
                    && this.getAge() == b.getAge()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        People p = null;
        try {
            p = (People) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
         return p ;
    }
}

接下来我们进行测试:

    @Test
    public void test3()throws CloneNotSupportedException{
        People p1 = new People("1","zhang3",12,new Student("1","teacher"));
        People p2 = (People) p1.clone();
        System.out.println(p1==p2);// 输出 false
        p1.setUsername("li4");
        System.out.println(p2.getUsername()); // 输出 zhang3
        p1.getStu().setClassNo("2");
        System.out.println(p2.getStu().getClassNo()); // 输出 2
        System.out.println(p1.getStu()==p2.getStu());// 输出 true
    }

 上述结果表明 当我们在进行浅克隆的时候 如果这个对象 存在对其他对象的引用,那么克隆后的引用值,和原对象的引用是一样的,如下图所示

 

3、深克隆: 顾名思义 跟浅克隆相比的区别是 克隆后的对象的对其他对象引用与原对象不同。

实现方式:

  • 引用对象也实现 Cloneable 接口 重载 clone()方法 ,并用public修饰
  • 在People对象的 clone 方法中增加 引用对象的 克隆方法
package com.wcly.activemqTest;

public class Student implements Cloneable {

    private String classNo;
    private String teacherName ;

    public String getTeacherName() {
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }

    public String getClassNo() {
        return classNo;
    }

    public void setClassNo(String classNo) {
        this.classNo = classNo;
    }

    public Student(String classNo, String teacherName) {
        this.classNo = classNo;
        this.teacherName = teacherName;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        Student stu = null;
        try {
            stu = (Student) super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return stu ;
    }
}
    @Override
    public Object clone() throws CloneNotSupportedException {
        People p = null;
        try {
            p = (People) super.clone();
            p.stu = (Student)stu.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
         return p ;
    }

接下来 我们看下测试代码:

    @Test
    public void test3()throws CloneNotSupportedException{
        People p1 = new People("1","zhang3",12,new Student("1","teacher"));
        People p2 = (People) p1.clone();
        System.out.println(p1==p2);// 输出 false
        p1.setUsername("li4");
        System.out.println(p2.getUsername()); // 输出 zhang3
        p1.getStu().setClassNo("2");
        System.out.println(p2.getStu().getClassNo()); // 输出 1
        System.out.println(p1.getStu()==p2.getStu());// 输出 false
    }

 

你可能感兴趣的:(java基础)