• 关于Java中clone


    原文链接:https://blog.csdn.net/zhaoheng314/article/details/81985880

    Java实现克隆需要遵循以下规则:

    1. 必须实现Cloneable接口
    2. 实现Cloneable的类应该重写clone(),重写时该方法的修饰符为public。
    public class CloneTest {
        public static void main(String[] args) {
            Student stu = new Student();
            stu.setName("张三");
            stu.setAge(10);
            Classes classes = new Classes();
            classes.setClassId(101);
            classes.setClassName("一班");
            stu.setClasses(classes);
            try {
                System.out.println("浅克隆测试------"); //克隆
                Student stu2 = (Student) stu.clone();
                System.out.println("两个对象是否相同:" + (stu == stu2));
                System.out.println("两个对象的name属性是否相同:" + (stu.getName() == stu2.getName()));
                System.out.println("两个对象的classes属性是否相同:" + (stu.getClasses() == stu2.getClasses()));
                System.out.println("浅克隆,Stu " + stu);
                System.out.println("浅克隆,Stu2 " + stu);
                System.out.println("修改克隆对象属性");
                stu2.setName("李四");//修改姓名
                stu2.setAge(20);//修改年龄
                stu2.getClasses().setClassId(102);//修改班级编号
                stu2.getClasses().setClassName("二班");//修改班级名称
                System.out.println("修改克隆对象属性后,Stu " + stu);
                System.out.println("修改克隆对象属性后,Stu2 " + stu2);
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    
    
    }
    
    @Data
    class Classes{
        private int classId;
        //基本类型
        private String className;//引用类型 //这里省略gettters and setters
    
        @Override
        public String toString() {
            return "Classes [classId=" + classId + ", className=" + className + "]";
        }
    //    @Override
    //    public Object clone() throws CloneNotSupportedException {
    //        return super.clone();
    //    }
    }
    
    @Data
    class Student implements Cloneable {
        private String name;//引用类型
        private int age;//基本类型
        private Classes classes;//引用类型 //这里省略gettters and setters
    
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", classes=" + classes + "]";
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            Student stu = (Student) super.clone();
    //        Classes cla = (Classes)classes.clone();
    //        stu.setClasses(cla);
            return stu;
        }
    }
    结果:
    浅克隆测试------
    两个对象是否相同:false
    两个对象的name属性是否相同:true
    两个对象的classes属性是否相同:true
    浅克隆,Stu Student [name=张三, age=10, classes=Classes [classId=101, className=一班]]
    浅克隆,Stu2 Student [name=张三, age=10, classes=Classes [classId=101, className=一班]]
    修改克隆对象属性
    修改克隆对象属性后,Stu Student [name=张三, age=10, classes=Classes [classId=102, className=二班]]
    修改克隆对象属性后,Stu2 Student [name=李四, age=20, classes=Classes [classId=102, className=二班]]

    通过Debug观察属性和运行测试类得到的结果,可以发现原始对象stu和克隆对象stu2不是同一对象,但是两个对象的name属性和classes属性是同一个对象,并且原始对象stu和克隆对象stu2的属性值是相等的,这也验证了“Java的克隆机制是对类的实例的属性逐一复制”。name属性和classes同为引用类型的实例,克隆后原始对象stu和克隆对象stu2的name属性和classes属性是同一对象,说明没有实现Cloneable接口的类的实例克隆是通过传引用实现的。

    修改了克隆对象stu2的各个属性后,可以发现:原始对象stu的classes属性跟随克隆对象stu2的classes属性变化了,但name和age属性没有跟随变化,这是为什么呢?

    age属性没有跟随变化比较容易理解,因为age属性是int类型,基本类型克隆时只是传值,不存在传引用。

    同样是传引用,为什么name属性没有跟随变化,难道name属性有特别之处?name属性是String类型,String类型也没有实现Conleable啊,很是困惑。

    回忆下String类的声明,public final class String implements …,final关键字是不是很可疑呢?再想想final关键字的作用,一是不可变,二是禁止指令重排。不可变,不可变,是不是想到什么了?正是因为String不可变的特性,克隆对象stu2并没有修改name属性的值,而是修改了name属性的引用。这就是为什么name属性没有跟随克隆对象的变化而变化,String不可变好像让浅克隆变为了深克隆。

    public class CloneTest {
        public static void main(String[] args) {
            Student stu = new Student();
            stu.setName("张三");
            stu.setAge(10);
            Classes classes = new Classes();
            classes.setClassId(101);
            classes.setClassName("一班");
            stu.setClasses(classes);
            try {
                System.out.println("浅克隆测试------"); //克隆
                Student stu2 = (Student) stu.clone();
                System.out.println("两个对象是否相同:" + (stu == stu2));
                System.out.println("两个对象的name属性是否相同:" + (stu.getName() == stu2.getName()));
                System.out.println("两个对象的classes属性是否相同:" + (stu.getClasses() == stu2.getClasses()));
                System.out.println("浅克隆,Stu " + stu);
                System.out.println("浅克隆,Stu2 " + stu);
                System.out.println("修改克隆对象属性");
                stu2.setName("李四");//修改姓名
                stu2.setAge(20);//修改年龄
                stu2.getClasses().setClassId(102);//修改班级编号
                stu2.getClasses().setClassName("二班");//修改班级名称
                System.out.println("修改克隆对象属性后,Stu " + stu);
                System.out.println("修改克隆对象属性后,Stu2 " + stu2);
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    
    
    }
    
    @Data
    class Classes implements Cloneable{
        private int classId;
        //基本类型
        private String className;//引用类型 //这里省略gettters and setters
    
        @Override
        public String toString() {
            return "Classes [classId=" + classId + ", className=" + className + "]";
        }
        @Override
        public Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    @Data
    class Student implements Cloneable {
        private String name;//引用类型
        private int age;//基本类型
        private Classes classes;//引用类型 //这里省略gettters and setters
    
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", classes=" + classes + "]";
        }
    
        @Override
        public Object clone() throws CloneNotSupportedException {
            Student stu = (Student) super.clone();
            Classes cla = (Classes)classes.clone();
            stu.setClasses(cla);
            return stu;
        }
    }

    深克隆测试------
    两个对象是否相同:false
    两个对象的name属性是否相同:true
    两个对象的classes属性是否相同:false
    深克隆,Stu Student [name=张三, age=10, classes=Classes [classId=101, className=一班]]
    深克隆,Stu2 Student [name=张三, age=10, classes=Classes [classId=101, className=一班]]
    修改克隆对象属性
    修改克隆对象属性后,Stu Student [name=张三, age=10, classes=Classes [classId=101, className=一班]]
    修改克隆对象属性后,Stu2 Student [name=李四, age=20, classes=Classes [classId=102, className=二班]]

    通过Debug观察属性和运行测试类得到的结果,克隆后原始对象stu和克隆对象stu2的classes属性不是同一个对象。修改了克隆对象stu2的各个属性后,可以发现:原始对象stu的属性不再跟随克隆对象stu2的属性变化而变化。

    通过对Java克隆机制的学习和检验,我们得出一个结论:如果要对某个类的的实例的引用类型属性实现深克隆,要求引用类型属性对于的类实现Cloneable接口并重写clone()。

  • 相关阅读:
    Javascript面向对象(三):非构造函数的继承
    Javascript面向对象(二):构造函数的继承
    Javascript 面向对象(一):封装
    .NET面试题系列[12]
    .NET面试题系列[11]
    .NET面试题系列[10]
    .NET面试题系列[9]
    .NET面试题系列[8]
    .NET面试题系列[7]
    .NET面试题系列[6]
  • 原文地址:https://www.cnblogs.com/bokai/p/11584258.html
Copyright © 2020-2023  润新知