[JavaSE] Clonable(深克隆,浅克隆)

目录

往期回顾,专栏一览

🔴 Clonable

🔵 对象创建

🔵 调用方法   

🔵 小结:一个对象如何被克隆?

🔵 面试问题

🔵 代码升华!浅拷贝?

🔵 深拷贝实现!


🍹欢迎各路大佬来到 Nick 主页指点


☀️本期文章将学习 [JavaSE] Clonable 克隆,我是博主Nick。✨


✨我的博客主页:Nick_Bears 🌹꧔ꦿ


🌹꧔ꦿ博文内容如对您有所帮助,还请给个点赞 + 关注 + 收藏✨

  

🔴 Clonable

  

🔵 对象创建

💬 创建对象的几种方式?

  

  1. new
  2. 克隆方法

      

class Person{
    public String name;
    public Money money = new Money();

    public void play() {
        System.out.println("敲代码");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=" + name +
                '}';
    }

public class Demo {
    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = person.clone();
    }
}

   

🔸 我们发现 clone() 是爆红的,我们查看  clone() 的源码试试

   

🔸 于是改成

Person person1 = (Person)person.clone();

  

🔸 恶心的是仍然报错!!!通过学习,我们知道一个对象实现 clone 说明该对象是可克隆的!于是在被克隆类上实现 Cloneable 接口。

class Person implements Cloneable{
    public int age;

    public void play(){
        System.out.println("玩!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
    

    //快捷键:Ctrl + O
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

     

     

🔸 我们发现 clone() 还是爆红的,那么我们抛一下异常

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        //并且抛出异常即可
        Person person1 = (Person) person.clone();
    }
}

   

🔵 调用方法   

💬  思考:person 默认继承 Object,为什么通过引用不能调用克隆方法?

   

 答:可以调用,只是 clone 比较特殊,只是我们必须要重写。

   

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

      

🔸 我们已经调用了 clone() 方法,他会帮我们做什么事情?产生一个副本!

  

🔵 小结:一个对象如何被克隆?

  • 必须实现 Cloneable 接口
  • 重写 Object 的 clone() 方法
  • 调用方法抛异常

   

💠 输出克隆的对象

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.age = 99;
        Person person1 = (Person) person.clone();
        System.out.println(person1);
    }
}

//输出
Person{age=99}

   

💠 修改克隆对象的值,查看克隆值和原来的值

public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.age = 99;
        Person person1 = (Person) person.clone();
        System.out.println(person1);

        System.out.println("====================");
        person1.age=199;
        System.out.println(person);
        System.out.println(person1);
    }
}

//输出
Person{age=99}
====================
Person{age=99}
Person{age=199}

  

💬 上面这个代码是深拷贝吗?

   

答:决定是 深拷贝 还是 浅拷贝 不是某一个方法的使用,或者对应哪种数据类型,而是代码的实现,就是你的代码是如何写的,处理过程如何!我只能说在这种情况下这是深拷贝。

   

🔵 面试问题

  • 思考:你知道Clonable接口吗?
  • 思考:为啥这接口是个空接口?
  • 思考:有啥作用?

   

答:空接口->标志接口->代表当前类可以被克隆。

     

🔵 代码升华!浅拷贝?

🔹 我给 Person 新增了一个 Money 属性

class Money{
    public double m = 13.14;
}
class Person implements Cloneable{
    public int age;
    public Money money = new Money();

    public void play(){
        System.out.println("玩!");
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
    }

   

     

🔹 我们通过图推测下面的代码运行都是13.14

   

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
        System.out.println("================");
    }
//结果
13.14
13.14
================

      

🔹 那么我们现在来改掉一个值,可想而知都是同一个引用

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
        System.out.println("================");
        person1.money.m = 1314;
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
    }
//结果
13.14
13.14
================
1314.0
1314.0

🔹 对于目前情况来说,这是一个浅拷贝,那么我们如何实现深拷贝呢?我们是不是应该也把 Money 复制一份呢?

        

🔵 深拷贝实现!

🔹 我们在上面代码的基础上添加一些代码,对 Money 也连接克隆接口,并且重写

class Money implements Cloneable {
    public double m = 13.14;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

   

🔹 这样以后我们就能对 Money 也拷贝一份(在 Person 的方法中)

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        //把钱也拷贝一份
        tmp.money = (Money)this.money.clone();
        //return super.clone();
        return tmp;
    }

      

     

🔹 此时我们再次测试刚刚的方法

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
        System.out.println("================");
        person1.money.m = 1314;
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
    }
//运行结果
13.14
13.14
================
13.14
1314.0

      

🔵 代码一览

package 接口.常用接口.Clonable;
/**
 * 1、面试问题:
 * 你知道Cloneable接口吗?
 * 为啥这个接口是一个空接口?
 * 有啥作用? 空接口->标志接口->代表当前这个类是可以被克隆的
 * 2、创建对象的方式
 * 1.new
 * 2.克隆方法
 */
class Money implements Cloneable{
    public double m = 10000;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Person implements Cloneable {
    public String name;
    public Money money = new Money();

    public void play() {
        System.out.println("玩王者");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=" + name +
                '}';
    }

    /**
     *
     * tmp.money = (Money) this.money.clone(); 我把克隆出来的tmp中的money也给克隆一份
     * @return 我以前返回的就是一个tmp,现在是已经克隆好 money 的 tmp;
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp =(Person)super.clone();
        tmp.money = (Money) this.money.clone();
//        return super.clone();
        return tmp;
    }
}


public class Demo {

    /**
     * 克隆
     * 特殊点:想要调用clone,必须先重写(尽管都是继承于Object下的)
     *
     * 决定深拷贝还是浅拷贝取决于代码的实现,而不是某一个方法
     * @param args
     */
    public static void main1(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        person.name = "Nick";
        Person person1 = (Person) person.clone();
        System.out.println(person1);

        System.out.println("============================");
        person1.name = "Nicks";
        System.out.println(person1);
        System.out.println(person);
//执行结果
//        Person{name=Nick}
//============================
//        Person{name=Nicks}
//        Person{name=Nick}
    }

    /**
     * 浅克隆
     * 通过此方法运行流程来看,这个浅克隆
     *
     * 思考?如何实现深拷贝呢?
     * 我们通过接口来拷贝对象,那么我们重写接口试试...
     *
     */
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();
        Person person1 = (Person) person.clone();
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
        System.out.println("===============================");
        person1.money.m = 999999;
        System.out.println(person.money.m);
        System.out.println(person1.money.m);
//运行结果(重写接口前)
//        10000.0
//        10000.0
//        ==============================
//        999999.0
//        999999.0
    }

//运行结果(重写接口后)
//        10000.0
//        10000.0
//        ===============================
//        10000.0
//        999999.0
}

  • 43
    点赞
  • 30
    收藏
  • 打赏
    打赏
  • 48
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:Age of Ai 设计师:meimeiellie 返回首页
评论 48

打赏作者

Nick_Bears

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值