• java核心技术卷案例_克隆


    克隆的正常使用

    .clone() 方法是 Object 类的一个 protected 方法

    protected native Object clone() throws CloneNotSupportedException;
    
    • 1

    也就是说子类无法直接继承 Object 的 clone() 方法,只能在子类中通过 super 关键字来调用
    而且 clone() 返回的数据类型是 Object ,但我们通常想直接克隆出一个同类型的新对象.
    因此,我们需要自己在子类中自己声明一个 clone() 方法,在方法中用 super 关键字调用Object.clone()
    然后在强转成想用类型的对象返回,完成一次克隆

    	// Person 类
        static class Person {
            private Pocket pocket; // 包含一个引用对象
    		
    		/** 声明一个克隆方法 */
            public Person clone() throws CloneNotSupportedException {
                return (Person) super.clone();
            }
        }
        // Pocket 类
    	static class Pocket {
            private int mony;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    尝试克隆

    	public static void main(String[] args) {
            Person person1 = new Person();
            Pocket pocket = new Pocket();
            pocket.mony = 100;
            person1.pocket = pocket;
            Person person2 = null;
            try {
                person2 = person1.clone(); // 克隆
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    执行结果:
    在这里插入图片描述
    原因是少了一个步骤,要使用 super.clone() ,必须要实现一个标记接口 Cloneable,表示这个类是可以克隆的,所以我们修改一下

    	// Person 类
        static class Person implements Cloneable {
            private Pocket pocket; // 包含一个引用对象
    		
    		/** 声明一个克隆方法 */
            public Person clone() throws CloneNotSupportedException {
                return (Person) super.clone();
            }
        }
        // Pocket 类
    	static class Pocket {
            private int mony;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    再次执行就没问题啦

    克隆是浅拷贝

    上面的案例中 Person 对象中包含一个 Pocket 类型的引用
    我们试试用 person1 克隆出 person2 后修改 person1 引用对象的 mony 属性,看看 person2 的 mony 有没有变化

    public static void main(String[] args) {
            Person person1 = new Person();
            Pocket pocket = new Pocket();
            pocket.mony = 100;
            person1.pocket = pocket;
            Person person2 = null;
            try {
                person2 = person1.clone(); // 克隆
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            System.out.println("修改前person1.pocket.mony = " + person1.pocket.mony);
            if (!ObjectUtils.isEmpty(person2)) {
                System.out.println("修改前person2.pocket.mony = " + person2.pocket.mony);
            }
            person1.pocket.mony = 200; // 修改 person1 的 pocket 对象的 属性值
            System.out.println("修改后person1.pocket.mony = " + person1.pocket.mony);
            if (!ObjectUtils.isEmpty(person2)) {
                System.out.println("修改后person2.pocket.mony = " + person2.pocket.mony);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    结果
    在这里插入图片描述
    就是说克隆对于引用变量是拷贝了一份引用,而没有把引用指向的对象也给克隆一个新的对象再引用它
    那么实现深克隆就要手动去把 Person 类的所有引用对象给克隆一份,可以之间new对象赋值,也可以让Pocket 对象也实现 Cloneable 接口用.clone() 方法克隆

    	static class Person implements Cloneable {
            private Pocket pocket;
    
            public Person clone() throws CloneNotSupportedException {
                Person clone = (Person) super.clone();
                Pocket newPocket = new Pocket();
                newPocket.mony = clone.pocket.mony;
                clone.pocket = newPocket; // 引用新对象
                return clone;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果
    在这里插入图片描述
    这样表示克隆出来的就是一个船新的对象啦

    小疑问

    如果一个对象的引用链非常长非常深,那要深拷贝一个对象不是麻烦死?
    要一层一层 new 对象赋值?
    看来克隆只适合引用层比较浅的对象啊
    我直接用 BeanUtils.copy() 不香吗?
    啥?BeanUtils.copy()也是浅拷贝?

  • 相关阅读:
    从零开始基于LLM构建智能问答系统的方案
    2023年Q3乳品行业数据分析(乳品市场未来发展趋势)
    大数据存储ClickHouse
    Spring Boot 2.x源码系列【2】启动流程深入解析之SpringApplication类
    非技术背景项目经理如何发展?
    where 1=1 是什么意思
    湖北省2022年高企申报奖励补贴以及申报材料流程讲解(认定条件要求内容)
    k8s--架构基础--cgroup v2
    MySQL数据库 主从复制与读写分离
    HBase shell常用命令
  • 原文地址:https://blog.csdn.net/qq_31856061/article/details/125628644