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

news2024/11/26 16:36:40

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

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

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

Student stu1 = new Student(); 
Student stu2 = stu1; 

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

1、浅克隆

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

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

package com.ffyc.javapro.objectClone.demo1;
public class Person implements  Cloneable{
    int num;
    String name;
    
    //get和set方法...

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}
package com.ffyc.javapro.objectClone.demo1;
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(100,"jim");//原型对象
        Person p2 =p1.clone();//克隆的新对象
        System.out.println(p1==p2);//false,实现了克隆
    }
}

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

public class Address{
    String  address;
	//get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();//对象中关联着另一个对象,只是将关联对象的地址复制过来了,并没有重新创建一个新的关联对象
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向了一个对象

        System.out.println(p1); // jim  西安
        System.out.println(p2); // tom  西安
    }
}

2、深克隆

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

克隆方式:

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

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

public class Address  implements Cloneable{//实现了Cloneable接口
    String  address;
   //get和set方法...
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

    @Override
    protected Address clone() throws CloneNotSupportedException {//重写Object中的clone方法
        return (Address)super.clone();
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;   
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        person.address = (Address)address.clone();//深度复制  联同person中关联的对象也一同克隆.
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向不同的对象

        System.out.println(p1); // jim   西安
        System.out.println(p2); // tom   汉中
    }
}

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

import java.io.Serializable;
public class Address  implements Serializable {
     String  address;
    //get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
import java.io.*;
public class Person implements Serializable {
     int num;
     String name;
     Address address;
    //get和set方法...
    
    //自定义克隆方法
    public Person myclone() {
        Person person = null;
          try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ObjectOutputStream oos = new ObjectOutputStream(baos);
                  oos.writeObject(this);
        		// 将流序列化成对象
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bais);
                 person = (Person) ois.readObject();
              } catch (IOException e) {
                 e.printStackTrace();
              } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         return person;
      }


    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.myclone();
        p2.setName("tom");
        address.setAddress("西安");

        System.out.println(p1);
        System.out.println(p2);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1190708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【c++】——类和对象(中)——赋值运算符重载

作者:chlorine 专栏:c专栏 你站在原地不动,就永远都是观众。 【学习目标】 拷贝复制——赋值运算符重载 目录 🎓运算符重载的初步认识 🌈运算符重载 🌈赋值运算符重载格式 (上) 🌈operator__判断俩个日期是否相等 &#x…

万宾科技智能井盖,实现对井盖的监测

随着人工智能和物联网技术的不断变化,各种适用于市政府提高管理能力和公共服务水平的高科技产品不断更新。在道路基础设施建设过程中,智能井盖传感器的出现时刻保护着城市地下生命线,而且可以对地下水道井盖进行实时的监测并完成数据上传等工…

Elastic Observability 8.11:ES|QL、APM 中的通用分析和增强的 SLOs

作者:Tom Grabowski, Katrin Freihofner, Israel Ogbole Elastic Observability 8.11 引入了 ES|QL for Observability(技术预览版)、Universal ProfilingTM 和 Elastic APM 集成,以及针对 Elastic Observability 的新 SLO &#…

判断sparse matrix是否是对称矩阵

参考: https://stackoverflow.com/questions/48798893/error-in-checking-symmetric-sparse-matrix import scipy.sparse as sp import numpy as np np.random.seed(1)a sp.random(5, 5, density0.5)a结果如下 sym_err a - a.T sym_check_res np.all(np.abs(s…

docker influxdb

docker & influxdb 搜索镜像 docker search influxdb docker pull influxdb: 1.4.2 docker run -d -p 8086:8086 --name influxdb influxdb:1.4.2 docker exec -it influxdb bash 连接influxdb 控制台 influx -host localhost -port 8086 influx -username root -passw…

docker部署mongodb

1:拉去momgodb镜像 2:拉去成功后,通过docker-compose.yml配置文件启动mongodb,docker-compose.yml配置如下 version: 3.8 services:mongodb-1:container_name: mongodbimage: mongo ports:- "27017:27017"volumes:- G:…

ESP8266 WiFi模块快速入门指南

ESP8266是一种低成本、小巧而功能强大的WiFi模块,非常适合于物联网和嵌入式系统应用。本指南将为您提供关于ESP8266 WiFi模块的快速入门步骤和基本知识。 第一步:硬件准备 首先,您需要将ESP8266 WiFi模块与您的开发板连接。通常情况下&#…

简单好看个人引导页毛玻璃页面 HTML 源码

毛玻璃个人引导页源码,界面简洁,已测可完美搭建,UI非常不错的,有兴趣的自行去安装体验吧,其它就没什么好介绍的了。 学习资料源代码:百度网盘 请输入提取码:ig8c

代挂单页网址发布页+加盟代理+APP下载页源码

代挂单页加盟代理网址发布页app下载页HTML单页版本,自行修改源码内文字。自行修改联系方式、登录地址!上传即可使用。源码我已全部打包好,直接上传本站提供的源码,无后台,直接访问即可! 源码下载&#xff…

Termius for Mac:掌控您的云端世界,安全高效的SSH客户端

你是否曾经在Mac上苦苦寻找一个好用的SSH客户端,让你能够远程连接到Linux服务器,轻松管理你的云端世界?现在,我们向你介绍一款强大而高效的SSH客户端——Termius。 Termius是一款专为Mac用户设计的SSH客户端,它提供了…

SPASS-探索性分析

探索性分析的意义 探索性分析更加强大,它是一种在对资料的性质、分布特点等完全不清楚的情况下,对变量进行更深入研究的描述性统计方法。在进行统计分析前,通常需要寻求和确定适合所研究的问题的统计方法, SPSS提供的探索性分析是解决此类问题的有效办法 探索性分析提供了很…

Vue3全局共享数据

目录 1,Vuex2,provide & inject2,global state4,Pinia5,对比 1,Vuex vue2 的官方状态管理器,vue3 也是可以用的,需要使用 4.x 版本。 相对于 vuex3.x,有两个重要变…

Hive 常用存储、压缩格式

1. Hive常用的存储格式 TEXTFI textfile为默认存储格式 存储方式&#xff1a;行存储 磁盘开销大 数据解析开销大 压缩的text文件 hive 无法进行合拆分 SEQUENCEFILE sequencefile二进制文件&#xff0c;以<key,value>的形式序列到文件中 存储方式&#xff1a;行存储 可…

贾扬清开源 AI 框架 Caffe | 开源英雄

【编者按】在开源与人工智能的灿烂星河里&#xff0c;贾扬清的名字都格外地耀眼。因为导师 Trevor Darrell 教授的一句“你是想多花时间写一篇大家估计不是很在意的毕业论文&#xff0c;还是写一个将来大家都会用的框架&#xff1f;”&#xff0c;学生贾扬清一头扎进了创 Caffe…

零代码+分布式微服务架构打造新一代一站式服务集成平台

目 录 01 项目背景 02 普元ESB产品介绍 03 新版本功能特性 04 应用案例‍‍‍‍ 05 展望与发展 01 项目背景 企业在实现数字化转型的过程中&#xff0c;随着信息化程度的提高&#xff0c;越来越多的企业开始采用微服务架构来构建自己的业务系统,各种系统之间的集成、数据共享…

计算机网络:概述

0 学时安排及讨论题目 0.1讨论题目&#xff1a; CSMA/CD协议交换机基本原理ARP协议及其安全子网划分IP分片路由选择算法网络地址转换NATTCP连接建立和释放再论网络体系结构 0.2 本节主要内容 计算机网络在信息时代中的作用 互联网概述 互联网的组成 计算机网络在我国的发展 …

【vector题解】连续子数组的最大和 | 数组中出现次数超过一次的数字

连续子数组的最大和 连续子数组的最大和_牛客题霸_牛客网 描述 输入一个长度为n的整型数组array&#xff0c;数组中的一个或连续多个整数组成一个子数组&#xff0c;子数组最小长度为1。求所有子数组的和的最大值。 要求:时间复杂度为 O(n)&#xff0c;空间复杂度为 O(n) 进…

Java算法(五):手写数组逆置API方法,实现数组逆置。 while实现 for循环实现

Java算法&#xff08;五&#xff09; while 循环实现 需求&#xff1a; 已知一个数组&#xff0c;arr {11, 22, 33, 44, 55};使用程序实现把数组中的元素交换位置。 交换后的数组为 arr {55, 44, 33, 22, 11}; 并在控制台输出交换后的数组元素。 代码示例 package com.…

集成MCU的OTP-2.4G合封芯片XL2401D,收发一体 上手简单

芯岭技术的XL2401D是一颗2.4G合封芯片&#xff0c;收发一体。合封芯片可以很好的节省PCB面积和开发成本。一颗芯片可以做到之前两颗芯片才能做到的事情。XL2401D内含MCU为九齐NY8A054E。有九齐MCU开发经验的话开发起来非常容易上手。 XL2401D芯片是工作在2.400~2.483GHz世界通…