【Java】:浅克隆和深克隆
创始人
2025-01-10 06:03:13
0

克隆

克隆和赋值

  • 克隆的结果是有多个相同的实体,各个对象指向不同的实体
  • 而多个不同对象指向一个相同的实体不是克隆,而是赋值

克隆的过程


  1. 首先实例化一个 student1 对象
    • 在堆里开辟了一块内存用来存储 age = 10 这个数据
  2. 调用 clone 方法
    • 在堆中又开辟了一块内存储存和 student1 指向内存区域一模一样的内容
  3. 将克隆后的数据内存地址赋值给 student2
    • student2 指向新克隆出来的区域

image.png|300

  • 但若想访问 clone 方法,需要满足:
    1. 重写 clone 方法,返回 super.clone()
      • 虽然 Object 类是所有类的父类,但它内部的 clone 方法是 protected 修饰的,只有在同包中才能访问,所以需要在新包中重写 clone 方法
      • return super.clone() 的意思就是调用父类(Object类)中的 clone 方法
    2. 强制类型转换调用 clone 方法的对象
      • 调用 clone 方法后的返回类型是 Object类,而调用 clone 方法的对象是 Student
      • 父类Object 需要强制类型转换成子类Student
    3. 需要抛出 CloneNotSuppertedException 异常
    4. 自定义类型必须实现 Clonable 接口
      • 这个接口中没有任何抽象方法
      • 此时这个接口叫做空接口/标记接口
      • 只有实现了这个克隆接口,才具备了可以被克隆的能力

代码

class Student implements Cloneable{     public int age = 10;      @Override   //重写clone方法     protected Object clone() throws CloneNotSupportedException {         return super.clone();     } }  public class Test {     public static void main(String[] args) throws CloneNotSupportedException {         Student student1 = new Student();         Student student2 = (Student)student1.clone();          System.out.println(student1.age);    //输出:10         System.out.println(student2.age);    //输出:10     } } 

浅克隆/浅拷贝


  • 浅克隆创建一个新的对象,但只复制原始对象的基本数据类型的字段或引用(地址),而不赋值引用指向的对象
  • 这意味着新对象和原始对象中的引用指向相同的对象
  • 如果对原始对象的引用类型属性进行修改,浅克隆的对象也会受到影响,因为它们引用了相同的堆内存

浅克隆的实现

class Money {     public double money = 12.5; }  class Student implements Cloneable{     public int age = 10;     public Money m = new Money();       @Override     protected Object clone() throws CloneNotSupportedException {         return super.clone();     } }  public class Test {     public static void main(String[] args) throws CloneNotSupportedException {         Student student1 = new Student();         Student student2 = (Student)student1.clone();          System.out.println(student1.m.money);  //输出:12.5         System.out.println(student2.m.money);  //输出:12.5         System.out.println("=========");         student1.m.money = 100;         System.out.println(student1.m.money);  //输出:100         System.out.println(student2.m.money);  //输出:100     } } 

观察输出结果可以发现:

  • 将 student1 指向的对象m中的 money 成员改变后,student2 指向的对象中的 money 成员的值也变成了相同的值

所以可知:

  • student1 和 student2 指向的 m 对象所指向的 money 成员是一样的
    image.png|466

深拷贝/深克隆

若想在当 student1 修改 money 的值的时候,student2 中的 money 的值不变,就需要使用深克隆了


  • 深克隆创建一个新的对象,并且递归地复制原始对象的所有字段和引用指向的对象,而不仅仅是复制引用本身
  • 深克隆会确保新对象和原始对象之间的所有关系都是独立的
  • 这意味着对新对象所做的修改不会影响到原始对象,因为他们拥有彼此独立的副本

深克隆的实现


  • 深克隆的实现过程image.png|559
    1. 首先实例化一个 student1 对象
      • 在堆里开辟了一块内存用来存储 age = 10m 这两个数据
        • m 是指向 Money 对象的指针或引用,这个 Money 对象里面有一个 money = 12.5 字段
    2. 调用clone 方法
      • 在堆中又开辟了一块内存,存储和 student1 一模一样的内容
    3. 将克隆后的数据所在堆中的地址赋值给 tmp
      • tmp 指向新克隆出来的内容的地址
    4. 克隆实例化的对象 Money
      • Money 类要支持 clone 方法
        • 要实现 Clonable 接口
        • 重写 clone 方法
    5. 将克隆出来的对象的地址赋值给 tmp 中的 m
      • 至此,两个对象分别指向不同的两个内容相同的实体
      • 实例中的引用变量间的修改也互不影响
    6. 返回 tmp
      • tmp 的指向地址赋值给 student2,克隆完成

class Money implements Cloneable{     public double money = 12.5;      @Override     protected Object clone() throws CloneNotSupportedException {         return super.clone();     } }  class Student implements Cloneable{     public int age = 10;     public Money m = new Money();       @Override     protected Object clone() throws CloneNotSupportedException {         Student tmp = (Student) super.clone();         tmp.m = (Money)this.m.clone();         return tmp;     } }  public class Test {     public static void main(String[] args) throws CloneNotSupportedException {         Student student1 = new Student();         Student student2 = (Student)student1.clone();          System.out.println(student1.m.money);  //输出:12.5         System.out.println(student2.m.money);  //输出:12.5         System.out.println("=========");         student1.m.money = 100;         System.out.println(student1.m.money);  //输出:100         System.out.println(student2.m.money);  //输出:12.5     } } 

相关内容

热门资讯

一分钟内幕!科乐吉林麻将系统发... 一分钟内幕!科乐吉林麻将系统发牌规律,福建大玩家确实真的是有挂,技巧教程(有挂ai代打);所有人都在...
一分钟揭秘!微扑克辅助软件(透... 一分钟揭秘!微扑克辅助软件(透视辅助)确实是有挂(2024已更新)(哔哩哔哩);1、用户打开应用后不...
五分钟发现!广东雀神麻雀怎么赢... 五分钟发现!广东雀神麻雀怎么赢,朋朋棋牌都是是真的有挂,高科技教程(有挂方法)1、广东雀神麻雀怎么赢...
每日必看!人皇大厅吗(透明挂)... 每日必看!人皇大厅吗(透明挂)好像存在有挂(2026已更新)(哔哩哔哩);人皇大厅吗辅助器中分为三种...
重大科普!新华棋牌有挂吗(透视... 重大科普!新华棋牌有挂吗(透视)一直是有挂(2021已更新)(哔哩哔哩)1、完成新华棋牌有挂吗的残局...
二分钟内幕!微信小程序途游辅助... 二分钟内幕!微信小程序途游辅助器,掌中乐游戏中心其实存在有挂,微扑克教程(有挂规律)二分钟内幕!微信...
科技揭秘!jj斗地主系统控牌吗... 科技揭秘!jj斗地主系统控牌吗(透视)本来真的是有挂(2025已更新)(哔哩哔哩)1、科技揭秘!jj...
1分钟普及!哈灵麻将攻略小,微... 1分钟普及!哈灵麻将攻略小,微信小程序十三张好像存在有挂,规律教程(有挂技巧)哈灵麻将攻略小是一种具...
9分钟教程!科乐麻将有挂吗,传... 9分钟教程!科乐麻将有挂吗,传送屋高防版辅助(总是存在有挂)1、完成传送屋高防版辅助透视辅助安装,帮...
每日必看教程!兴动游戏辅助器下... 每日必看教程!兴动游戏辅助器下载(辅助)真是真的有挂(2025已更新)(哔哩哔哩)1、打开软件启动之...