• java中的对象克隆(浅克隆和深克隆)


    在实际项目中,一个模型类需要为不同的层提供不同的模型。VO DO DTO

    需要将一个对象中的数据克隆到其他对象中。

    误区这种形式的代码复制的是引用,即对象在内存中的地址,stu1和stu2两个引用指向的是同一个对象

    1. Student stu1 = new Student();
    2. Student stu2 = stu1;

    数据类型分为:基本数据类型和引用数据类型,基本类型的值可以直接复制,引用类型只能复制引用地址。所以浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制

    1、浅克隆

    在克隆一个对象时,只复制它本身和其中值类型的成员变量,如果有关联的对象,只是将关联对象的引用地址复制过来,并没有创建一个新的关联对象。

    实现方式:类实现Cloneable接口,重写Object中的clone方法  

    1. package com.ffyc.javapro.objectClone.demo1;
    2. public class Person implements Cloneable{
    3. int num;
    4. String name;
    5. //get和set方法...
    6. @Override
    7. protected Person clone() throws CloneNotSupportedException {
    8. Person person = (Person)super.clone();
    9. return person;
    10. }
    11. @Override
    12. public String toString() {
    13. return "Person{" +
    14. "num=" + num +
    15. ", name='" + name + '\'' +
    16. '}';
    17. }
    18. }
    1. package com.ffyc.javapro.objectClone.demo1;
    2. public class Test {
    3. public static void main(String[] args) throws CloneNotSupportedException {
    4. Person p1 = new Person(100,"jim");//原型对象
    5. Person p2 =p1.clone();//克隆的新对象
    6. System.out.println(p1==p2);//false,实现了克隆
    7. }
    8. }

    以下案例中,有关联的对象address,只是将关联的对象的引用地址复制过来,并没有新创建关联对象,为浅克隆。

    1. public class Address{
    2. String address;
    3. //get和set方法...
    4. @Override
    5. public String toString() {
    6. return "Address{" +
    7. "address='" + address + '\'' +
    8. '}';
    9. }
    10. }
    1. public class Person implements Cloneable{
    2. int num;
    3. String name;
    4. Address address;
    5. //get和set方法...
    6. @Override
    7. protected Person clone() throws CloneNotSupportedException {
    8. Person person = (Person)super.clone();
    9. return person;
    10. }
    11. @Override
    12. public String toString() {
    13. return "Person{" +
    14. "num=" + num +
    15. ", name='" + name + '\'' +
    16. ", address=" + address +
    17. '}';
    18. }
    19. }
    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Address address = new Address();
    4. address.setAddress("汉中");
    5. Person p1 = new Person(100,"jim");
    6. p1.setAddress(address);
    7. Person p2 =p1.clone();//对象中关联着另一个对象,只是将关联对象的地址复制过来了,并没有重新创建一个新的关联对象
    8. p2.setName("tom");
    9. address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向了一个对象
    10. System.out.println(p1); // jim 西安
    11. System.out.println(p2); // tom 西安
    12. }
    13. }

    2、深克隆

    无论原型对象的成员变量是值类型还是引用类型(关联的对象),都将复制一份给克隆对象。(如果有关联的对象,将关联对象也会重新创建一个)

    克隆方式:

    1. 在关联的对象中,也实现Cloneable接口,重写Object中的clone方法,实现多级克隆,但是处理起来比较麻烦。
    2. 使用序列化方式,可以重写创建对象,包含关联的对象。

    案例一:相关联的类address也实现了Cloneable接口,重写Object中的clone方法,为深度克隆,但是很麻烦。

    1. public class Address implements Cloneable{//实现了Cloneable接口
    2. String address;
    3. //get和set方法...
    4. @Override
    5. public String toString() {
    6. return "Address{" +
    7. "address='" + address + '\'' +
    8. '}';
    9. }
    10. @Override
    11. protected Address clone() throws CloneNotSupportedException {//重写Object中的clone方法
    12. return (Address)super.clone();
    13. }
    14. }
    1. public class Person implements Cloneable{
    2. int num;
    3. String name;
    4. Address address;
    5. //get和set方法...
    6. @Override
    7. protected Person clone() throws CloneNotSupportedException {
    8. Person person = (Person)super.clone();
    9. person.address = (Address)address.clone();//深度复制 联同person中关联的对象也一同克隆.
    10. return person;
    11. }
    12. @Override
    13. public String toString() {
    14. return "Person{" +
    15. "num=" + num +
    16. ", name='" + name + '\'' +
    17. ", address=" + address +
    18. '}';
    19. }
    20. }
    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Address address = new Address();
    4. address.setAddress("汉中");
    5. Person p1 = new Person(100,"jim");
    6. p1.setAddress(address);
    7. Person p2 =p1.clone();
    8. p2.setName("tom");
    9. address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向不同的对象
    10. System.out.println(p1); // jim 西安
    11. System.out.println(p2); // tom 汉中
    12. }
    13. }

    案例二:实现了Serializable。把Person写到流里面,然后读进来,重新创建一个对象

    1. import java.io.Serializable;
    2. public class Address implements Serializable {
    3. String address;
    4. //get和set方法...
    5. @Override
    6. public String toString() {
    7. return "Address{" +
    8. "address='" + address + '\'' +
    9. '}';
    10. }
    11. }
    1. import java.io.*;
    2. public class Person implements Serializable {
    3. int num;
    4. String name;
    5. Address address;
    6. //get和set方法...
    7. //自定义克隆方法
    8. public Person myclone() {
    9. Person person = null;
    10. try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
    11. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    12. ObjectOutputStream oos = new ObjectOutputStream(baos);
    13. oos.writeObject(this);
    14. // 将流序列化成对象
    15. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    16. ObjectInputStream ois = new ObjectInputStream(bais);
    17. person = (Person) ois.readObject();
    18. } catch (IOException e) {
    19. e.printStackTrace();
    20. } catch (ClassNotFoundException e) {
    21. e.printStackTrace();
    22. }
    23. return person;
    24. }
    25. @Override
    26. public String toString() {
    27. return "Person{" +
    28. "num=" + num +
    29. ", name='" + name + '\'' +
    30. ", address=" + address +
    31. '}';
    32. }
    33. }
    1. public class Test {
    2. public static void main(String[] args) throws CloneNotSupportedException {
    3. Address address = new Address();
    4. address.setAddress("汉中");
    5. Person p1 = new Person(100,"jim");
    6. p1.setAddress(address);
    7. Person p2 =p1.myclone();
    8. p2.setName("tom");
    9. address.setAddress("西安");
    10. System.out.println(p1);
    11. System.out.println(p2);
    12. }
    13. }

  • 相关阅读:
    【蓝桥杯Web】第十三届蓝桥杯(Web 应用开发)第一次线上模拟赛
    SpringBoot一站式功能提供框架(二)Mybatis Plus分页、Websocket 消息推送、提取word--柚子真好吃
    Java EE——线程池
    PHP去除字符串前或后的字符或空格
    springboot+ssm+jsp疫苗接种管理系统
    ① 尚品汇的后台管理系统【尚硅谷】【Vue】
    langchain主要模块(四):Memory
    vuedraggable�拖拽列表设置某一条元素禁止被拖拽
    [BigData:Hadoop]:安装部署篇
    Mysql 表的约束
  • 原文地址:https://blog.csdn.net/m0_73503454/article/details/134322423