Java中的深克隆与浅克隆

news2025/1/11 0:46:51

浅克隆:

实现Cloneable接口即可实现,浅克隆只对象内部的基础数据类型(包括包装类)被克隆,引用数据类型(负责对象)会被使用引用的方式传递。
简单来说,就是浅克隆属性如果是复杂对象,对象是不会被复制一份的。
示例如下:

package com.comleader.utils.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author: Daisen.Z
 * @Date: 2023/3/10 9:53
 * @Version: 1.0
 * @Description:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Friend {
    private String name;
    private Integer age;
    private String home;
}

注意: 需要重新clone方法,将方法的protected改为public

package com.comleader.utils.test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Author: Daisen.Z
 * @Date: 2023/3/10 9:53
 * @Version: 1.0
 * @Description:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Cloneable {

    private String name;
    private Integer age;
    private String home;
    private Friend friend;

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

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person_old = new Person();
        person_old.setName("张三");
        person_old.setAge(18);
        person_old.setHome("chengdu");
        person_old.setFriend(new Friend("李四",19,"chongqin"));
        System.out.println("初始化下的person:" + person_old);

        Person person_clone = (Person) person_old.clone();

        person_clone.setName("张武");
        person_clone.setAge(19);
        person_clone.getFriend().setAge(20);

        System.out.println("克隆出来的person:" + person_clone);
        System.out.println("修改之后的person:" + person_clone);
        System.out.println("修改后的原person:" + person_old);
    }
}

运行Person中的main方法,
在这里插入图片描述
观察结果可以看出,修改Person的克隆对象的friend复杂属性时,原对象包括原对象的所有克隆对象friend熟悉都会被修改。
而修改String和Integer的则互不影响。

补充知识:

clonable接口的克隆方式,相比较于new对象的方式,不需要再计算内存分布,而是直接将内存区域分配给克隆对象,在大数据量的重复对象创建时可以使用clonable来优化性能。

深克隆:

深克隆的方式只能自己重新Cloneable方法或者序列化的方式实现。

重新克隆方法的方式:

1、 Friend实现Cloneable接口,并重写clone()方法。

@Data
@NoArgsConstructor
@AllArgsConstructor
class Friend implements Cloneable{
    private String name;
    private Integer age;
    private String home;

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

2、 更改Person中的clone()方法

@Data
@NoArgsConstructor
@AllArgsConstructor
class Person implements Cloneable{
    private String name;
    private Integer age;
    private String home;
    private Friend friend;

    @Override
    public Object clone() throws CloneNotSupportedException {
        Person person = (Person) super.clone();
        person.friend = (Friend) friend.clone();
        return person;
    }
}

这样克隆时,内部复杂对象也被克隆。

通过序列化对象的方式

如果当类中的属性存在数组(数组不能实现Cloneable接口)或者属性之间的关系比较复杂时,上面的方法都不能很好的实现深克隆了。

序列化的方式是让每个类都实现Serializable接口,然后通过序列化和反序列化操作达到深克隆的目的。

package test;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.*;

@Data
@NoArgsConstructor
@AllArgsConstructor
class Person implements Serializable{
    private String name;
    private Integer age;
    private String home;
    private Friend friend;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Friend implements Serializable {
    private String name;
    private Integer age;
    private String home;

}


public class CloneTest {
    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        Person person_old = new Person();
        person_old.setName("张三");
        person_old.setAge(18);
        person_old.setHome("chengdu");
        person_old.setFriend(new Friend("李四",19,"chongqin"));
        System.out.println("初始化下的person:" + person_old);

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(person_old);     //  序列化

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Person person_clone = (Person) objectInputStream.readObject();	//反序列化


        person_clone.setName("张武");
        person_clone.setAge(19);
        person_clone.getFriend().setAge(20);

        System.out.println("克隆出来的person:" + person_clone);
        System.out.println("修改之后的person:" + person_clone);
        System.out.println("修改后的原person:" + person_old);
    }
}

总结:

1、 浅克隆性能相比较new会有一些提高(很小),但是编码省了很多。
2、深克隆第一种实现方式同1。
3、深克隆的第二种实现方式在数据量多的情况下性能较差,但是当类熟悉特别多、对象占用空间特别大时会有较好效果,另外通过序列化可以将对象当前的形态以文件、IO流的方式保存下来,在需要时再进行加载转换,

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

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

相关文章

java多线程(二五)ReentrantReadWriteLock读写锁详解(1)

一、读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去…

有关3dmax对齐技巧的那些事

建模操作中,对齐是非常常用的一个功能,用好这个对齐功能能够事半功倍,好处我不说了,下面我们这篇博文就来说说3dmax对齐技巧的相关的内容。 文章目录一、点对齐1、样条线中的点对齐2、多边形中的点对齐二、线对齐三、面对齐四、物…

DJI ROS dji_sdk 源码分析|整体框架

DJI ROS dji_sdk 源码分析|整体框架launch文件CMakeLists.txtcpp文件main.cppOSDK 是一个用于开发无人机应用程序的开发工具包,基于OSDK 开发的应用程序能够运行在机载计算机上(如Manifold 2),开发者通过调用OSDK 中指定的接口能够…

计算机网络考研-第一章学

计算机网学习总结第一章计算机系统概述1.1.1 导学1.1.2 操作系统的特征1.2 操作系统的发展与分类1.3 操作系统的运行环境1.3.1 操作系统的运行机制1.3.2 中断和异常1.3.3系统调用:1.3.4 操作系统的体系结构第一章总结第一章计算机系统概述 1.1.1 导学 1.1.2 操作系…

Nginx 配置实例-反向代理案例一

实现效果:使用nginx反向代理,访问 www.suke.com 直接跳转到本机地址127.0.0.1:8080 一、准备工作 Centos7 安装 Nginxhttps://liush.blog.csdn.net/article/details/125027693 1. 启动一个 tomcat Centos7安装JDK1.8https://liush.blog.csdn.net/arti…

简单粗暴的分布式定时任务解决方案

分布式定时任务1.为什么需要定时任务?2.数据库实现分布式定时任务3.基于redis实现1.为什么需要定时任务? 因为有时候我们需要定时的执行一些操作,比如业务中产生的一些临时文件,临时文件不能立即删除,因为不清楚用户是…

基于FPGA实现正弦插值算法

1、正弦插值的算法分析 1.1 信号在时域与频域的映射关系 在进行正弦算法分析之前,我们回顾一下《数字信号处理》课程中,对于信号在时域与频域之间的映射关系,如下图。 对于上图中的原始信号x(t),使用ADC对信号进行采样&#xff0…

【操作系统】进程句柄

进程句柄句柄是什么为什么需要句柄作用句柄是什么 先给结论,句柄(handle)实际上是一个指向指针的指针。 它指向进程所要访问的进程对象的地址,是用来找到目标进程的索引,当我们想要访问对象进程时,就要利…

从一道面试题看 TCP 的吞吐极限

分享一个 TCP 面试题:单条 TCP 流如何打满香港到旧金山的 320Gbps 专线?(补充,写成 400Gbps 更具迷惑性,但预测大多数人都会跑偏,320Gbps 也就白给了) 这个题目是上周帮一个朋友想的,建议他别问三次握手&a…

C#:Krypton控件使用方法详解(第十六讲) ——kryptonCheckedListBox

今天介绍的Krypton控件中的kryptonCheckedListBox。下面介绍控件的外观属性如下图所示:Cursor属性:表示鼠标移动过该控件的时候,鼠标显示的形状。属性值如下图所示:UseWaitCursor属性:表示鼠标在控件中等待时&#xff…

问ChatGPT:零基础如何学好.Net Core?

更多开源项目请查看:一个专注推荐.Net开源项目的榜单 ChatGPT横空出世,一下子让全球互联网企业都慌了,纷纷表示:马上跟进发布ChatGPT,媒体纷纷报道大有改变教培行业。 下面我们问问ChatGPT:零基础如何学好…

EasyCVR视频融合平台开放插件功能:支持EasyNTS与EasyShark抓包

EasyCVR视频融合平台基于云边端一体化架构,具有强大的数据接入、处理及分发能力,平台支持海量视频汇聚管理,能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅…

GPS/GPRS车载定位系统智能终端设计μC/OS-Ⅱ调度液晶显示汽车行驶记录仪电路

wx供重浩:创享日记 对话框发送:gps电路 免费下载完整无水印论文报告(包含主板电路图和采集板电路图) 文章目录一、绪论二、车载智能终端三、车载智能终端的硬件结构及设计四、车载智能终端的软件结构及设计五、总结和展望附录一 汽…

小i机器人登陆纳斯达克:市值4.2亿美元,与苹果打了10年专利侵权官司

‍数据智能产业创新服务媒体——聚焦数智 改变商业要问当前科技圈里最靓的仔是谁?那当然是非 ChatGPT莫属。当下谁能推出真正意义上的中国版ChatGPT,并且在这轮AI浪潮竞争白热化阶段中笑到最后,已经成为人们关注的焦点。美东时间3月9日&…

使用chatgpt写6.5分作文范文

其实使用chatgpt最大的背单词好处就是你可以看到真正的外国人的思维到底是如何的。而且,你也可以看到chatgpt这个模型,如果是编写代码的话,你如果使用中文,它编写的效果是没有英文输入的好的,为什么呢?因为…

Vector - CAPL - log回放模块函数

Replay log回放模块作为我们常见的问题分析小工具,是大部分车载圈老人的必备工具,不过自从CANoe软件11.0之后的版本变动依然无法阻挡每一个车载人使用的热情,除了我们常见的手动回放log外,我们工作中还有一部分低概率以及极低概率出现的问题,这时候我们就需要通过自动化对…

python趣味编程-2048游戏

在上一期我们用Python实现了一个盒子追逐者的游戏,这一期我们继续使用Python实现一个简单的2048游戏,让我们开始今天的旅程吧~ 在 Python 免费源代码中使用 Tkinter 的简单 2048 游戏 使用 Tkinter 的简单 2048 游戏是一个用Python编程语言编码的桌面游…

阅读笔记DeepAR: Probabilistic Forecasting with Autoregressive Recurrent Networks

zi,t∈Rz_{i,t}\in \mathbb{R}zi,t​∈R表示时间序列iii在ttt时刻的值。给一个连续时间段t∈[1,T]t\in [1, T]t∈[1,T],将其划分为context window[1,t0)[1,t_0)[1,t0​)和prediction window[t0,T][t_0,T][t0​,T]。用context window的时间序列预测prediction window…

关于异常控制流和系统级 I/O:进程

💭 写在前面:本文将学习《深入理解计算机系统》的第六章 - 关于异常控制流和系统级 I/O 的 进程部分。CSAPP 是计算机科学经典教材《Computer Systems: A Programmers Perspective》的缩写,该教材由Randal E. Bryant和David R. OHallaron 合著…

C 去除字符串中重复字母(LeetCode)

🌟前言摆烂太久,好久没有更文了,小九和大家一起看看题写写题找回手感吧,也希望这篇文章可以帮助正在寻找解题答案的朋友,你们的支持就是我最大的动力!求三连!求关注呀!🌟…