Java对象的浅克隆和深克隆

Java - 对象克隆、Cloneable接口、浅克隆和深克隆 本文总结了Java中的Cloneable接口的作用及其使用方式,以及Java创建对象的四种方式。Cloneable接口是一个标记接口,实现它并重写Object中的clone方法才能成功克隆对象。Object的clone方法是浅拷贝,如果要执行深拷贝,需要按需重写clone方法。Java创建对象的方式包括new、clone、输入输出流和反射构造对象等。此外,本文还介绍了浅克隆和深克隆的概念和示例代码,并解释了为什么需要实现Cloneable接口才能实现深克隆。 阅读详情
 为什么需要克隆
     在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,用简单的赋值语句是不能满足这种需求的,要满足这种需求有很多途径。
 
    克隆的实现方式

      一、浅度克隆
    
      浅度克隆对于要克隆的对象,对于其基本数据类型的属性,复制一份给新产生的对象,对于非基本数据类型的属性,仅仅复制一份引用给新产生的对象,即新产生的对象和原始对象中的非基本数据类型的属性都指向的是同一个对象。

      浅度克隆步骤:
      1、实现java.lang.Cloneable接口
         要clone的类为什么还要实现Cloneable接口呢?Cloneable接口是一个标识接口,不包含任何方法的!这个标识仅仅是针对Object类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的 clone()方法(也就是调用了super.Clone()方法),那么Object的clone()方法就会抛出 CloneNotSupportedException异常。
 
     2、重写java.lang.Object.clone()方法
       JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
 
      观察一下Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于java中的非native方法。这也解释了为什么要用Object中clone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能。Object类中的clone()还是一个protected属性的方法,重写之后要把clone()方法的属性设置为public。
 
Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
 
Java代码实例:
public class Product implements Cloneable {   
    private String name;   
  
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}  
 
 
   二、深度克隆
     
     在浅度克隆的基础上,对于要克隆的对象中的非基本数据类型的属性对应的类,也实现克隆,这样对于非基本数据类型的属性,复制的不是一份引用,即新产生的对象和原始对象中的非基本数据类型的属性指向的不是同一个对象
 
      深度克隆步骤:
      要克隆的类和类中所有非基本数据类型的属性对应的类
        1、都实现java.lang.Cloneable接口
        2、都重写java.lang.Object.clone()方法
 
Java代码实例:
public class Attribute implements Cloneable {   
    private String no;   
       
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}   
  
public class Product implements Cloneable {   
    private String name;   
       
    private Attribute attribute;   
  
    public Object clone() {   
        try {   
            return super.clone();   
        } catch (CloneNotSupportedException e) {   
            return null;   
        }   
    }   
}   
 
 
      三、使用对象序列化和反序列化实现深度克隆
        所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。
 
对象的序列化还有另一个容易被大家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制大部分的对象,但是众所周知,Clone有深度Clone和浅度Clone,如果你的对象非常非常复杂,并且想实现深层 Clone,如果使用序列化,不会超过10行代码就可以解决。
 
虽然Java的序列化非常简单、强大,但是要用好,还有很多地方需要注意。比如曾经序列化了一个对象,可由于某种原因,该类做了一点点改动,然后重新被编译,那么这时反序列化刚才的对象,将会出现异常。 你可以通过添加serialVersionUID属性来解决这个问题(在Java序列化与反序列化学习(二):序列化接口说明 的标题三中有此说明)。如果你的类是个单例(Singleton)类,虽然我们多线程下的并发问题来控制单例,但是,是否允许用户通过序列化机制或者克隆来复制该类,如果不允许你需要谨慎对待该类的实现(让此类不用实现Serializable接口或Externalizable接口和Cloneable接口就行了)。
  
Java代码实例:
public class Attribute {   
    private String no;   
}   
  
public class Product {   
    private String name;   
       
    private Attribute attribute;   
  
    public Product clone() {   
        ByteArrayOutputStream byteOut = null;   
        ObjectOutputStream objOut = null;   
        ByteArrayInputStream byteIn = null;   
        ObjectInputStream objIn = null;   
           
        try {   
// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
            byteOut = new ByteArrayOutputStream();    
            objOut = new ObjectOutputStream(byteOut);    
            objOut.writeObject(this);   
  // 将流序列化成对象
            byteIn = new ByteArrayInputStream(byteOut.toByteArray());   
            objIn = new ObjectInputStream(byteIn);   
               
            return (ContretePrototype) objIn.readObject();   
        } catch (IOException e) {   
            throw new RuntimeException("Clone Object failed in IO.",e);      
        } catch (ClassNotFoundException e) {   
            throw new RuntimeException("Class not found.",e);      
        } finally{   
            try{   
                byteIn = null;   
                byteOut = null;   
                if(objOut != null) objOut.close();      
                if(objIn != null) objIn.close();      
            }catch(IOException e){      
            }      
        }   
    }   
} 
或者:
public static <T extends Serializable> T copy(T input) {
    ByteArrayOutputStream baos = null;
    ObjectOutputStream oos = null;
    ByteArrayInputStream bis = null;
    ObjectInputStream ois = null;
    try {
        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(baos);
        oos.writeObject(input);
        oos.flush();

        byte[] bytes = baos.toByteArray();
        bis = new ByteArrayInputStream(bytes);
        ois = new ObjectInputStream(bis);
        Object result = ois.readObject();
        return (T) result;
    } catch (IOException e) {
        throw new IllegalArgumentException("Object can't be copied", e);
    } catch (ClassNotFoundException e) {
        throw new IllegalArgumentException("Unable to reconstruct serialized object due to invalid class definition", e);
    } finally {
        closeQuietly(oos);
        closeQuietly(baos);
        closeQuietly(bis);
        closeQuietly(ois);
    }
}

也可以用json等其他序列化技术实现深度复制;

#########################注意######################
Bean复制的几种框架中(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)都是相当于克隆中的浅克隆。
1)spring包和Apache中的 BeanUtils     采用反射实现
    Spring: void copyProperties(Object source, Object target,String[] ignoreProperties)
    Apache:void  copyProperties(Object dest, Object orig)
2)cglib包中的  Beancopier   采用动态字节码实现
   cglib: BeanCopier create(Class source, Class target,boolean useConverter)
   例如:
          BeanCopier copier =BeanCopier.create(stuSource.getClass(), stuTarget.getClass(), false);
          copier.copy(stuSource, stuTarget, null);

公司内部对用到的bean属性复制做了下性能分析:
cglib   BeanCopier   15ms

Spring  BeanUtil      4031ms

apache BeanUtils      18514ms.
#########################注意######################

clone和BeanUtils.copyProperties对比:

Cloning is done by you. If the instance which you trying clone contains reference of another instance you have to write cloning code to that one too. What if the instances contains chain of references to other instances? So if you do cloning by yourself, there are chances that you might miss a small detail.

BeanUtils.copyProperties on otherhand take care of everything by itself. It reduces your effort.


STM32学习笔记(江协科技)-----OLED显示屏 SSD1306简介:•SSD1306是一款OLED/PLED点阵显示屏的控制器,可以嵌入在屏幕中,用于执行接收数据、显示存储、扫描刷新等任务••驱动接口:128个SEG引脚和64个COM引脚,对应128*64像素点阵显示屏••内置显示存储器(GDDRAM):128*64 bit128*8 ByteSRAM••供电:IC逻辑),VCC=7~15V(面板驱动)••通信接口:8位6800/8080并行接口,3/4线SPI。 阅读详情

相关推荐

别再死磕USB HID了!用ESP32的Arduino框架手把手教你实现蓝牙鼠标键盘(附完整代码)

本文详细介绍了如何使用ESP32的Arduino框架实现蓝牙HID设备,包括鼠标和键盘的快速开发。通过现成的库和示例代码,开发者可以轻松打造自定义蓝牙外设,无需复杂的USB HID协议栈,适用于演示控制器、宏键盘等多种场景。

weixin_31309419的博客 260

一个工具类让你彻底解决bean深拷贝

深拷贝是我们在代码开发当中经常需要使用到的,但是市面上的对象拷贝方法,比如spring自带的,或者其他工具类带的对象拷贝,大部分都是浅拷贝,根本无法满足咱们的业务需求,我们就只能对里面的引用对象进行专门的赋值动作,比较麻烦。今天我会为大家分享我在工作当中经常使用到的深拷贝工具类,并会为大家一一分析讲解,当前类已经在生产中实践过,没有什么问题,大家可以基于自己的实际情况进行使用。!

一个人的江湖 2306

PX4 Gazebo仿真进阶:自定义飞机模型和地图的完整指南

本文详细介绍了如何在PX4 Gazebo仿真中自定义飞机模型和地图模型,包括文件架构解析、参数调整指南、地图定制技巧及常见问题解决方案。通过实战步骤和性能优化建议,帮助开发者高效完成复杂场景的飞行控制算法测试。

weixin_29081101的博客 386

对象拷贝之Apache BeanUtils、Spring的BeanUtils、Mapstruct、BeanCopier、PropertieyUtils对比(深拷贝)

大多时候时候使用的是Apache或Spring``BeanUtils,今天,我们来看一下一个更高效的属性拷贝方式:BeanCopier。 https://github.com/cglib/cglib https://github.com/cglib/cglib/blob/master/cglib/src/main/java/net/sf/cglib/beans/BeanCopier.java 首先梳理出来现在有哪些对象拷贝的方式: Apache的BeanUtils:BeanUtils是Apach.

赵英超的博客 9837

Bugku中的source

进入环境后 我们首先查看源码可以得到一个flag 这肯定是个假的(已经提交过了确实是个假的) 题目提示要用Linux 这里使用的是kali 我们首先dirsearch一下这个网站 可以看到有.git文件泄露 也可以点开那个链接但是在里面没有找到flag 然后选择下载这个.git文件 然后进入这个文件夹 输入git reflog查看文件状态 可以看到有四个都有flag is here 一个一个查看git show 然后在40c6d51中发现了我们需要的fl

A272036149的博客 1011

逆向实战:手把手教你分析Google DroidGuard虚拟机的加密与反调试(附Python脚本)

本文深入解析Google DroidGuard虚拟机的加密机制与反调试策略,提供从环境配置到逆向分析的完整实战指南。通过IDA Pro、Frida等工具链,详细剖析DroidGuard的信号拦截、内存校验等保护机制,并附Python脚本实现自动化分析,助力Android安全研究人员突破GMS核心组件的安全防护。

weixin_32428571的博客 311

Spring当中的BeanUtils.copyProperties方法是深拷贝还是浅拷贝?

拷贝 : 顾名思义 ,在 Java当中就是 将一个类 的 属性 通过 get 和 set 方法来 赋值 给到 另一个类当中的属性 .浅拷贝 : 如果是引用类型 , 那么目标对象拷贝的只是源对象的地址 (无论目标对象还是源对象的改变 , 它们都会一起发生改变)[引用的一个内存地址]深拷贝 : 即将源对象的属性值 全部复制到 目标对象相应属性 (复制完之后,它们之间是隔开的 , 没有任何关系 , 无论操作源对象 还是目标对象 都是对另一个没有影响)[将子对象的属性也拷贝过去]

qq_70095877的博客 1627

金融波动率的“捕手”:GARCH模型,揭秘市场波动的“聚集密码”

摘要: GARCH模型(广义自回归条件异方差)是金融时间序列分析中用于捕捉“波动聚类”现象的核心工具。传统模型(如ARIMA)无法刻画金融数据的时变波动特性,而GARCH通过建模条件方差的动态变化(如$\sigma_t^2 = \omega + \alpha \varepsilon_{t-1}^2 + \beta \sigma_{t-1}^2$),精准预测波动率。Python实战显示,GARCH能有效拟合模拟金融数据的波动聚类,残差无自相关,验证了其优越性。该模型在波动率预测、风险价值(VaR)计算和期权定

u010257409的博客 2055

使用BeanCopier工具类拷贝JavaBean

JavaBean拷贝 深拷贝和浅拷贝概念 浅拷贝 Shallow Copy 对基本类型的属性会进行值传递,当修改其中一个对象中的属性时,不会影响另一个对象中的属性 对引用数据的属性,比如数组或某类对象,会进行引用传递,及两个对象中的属性指向同一个实例对象,修改对象会相互影响。 深拷贝 Deep Copy 深拷贝就是对引用类型的数据,也进行拷贝,开辟新的内存空间,两个bean之间相互修改自己的属性不产生影响。 开源工具类 apache的BeanUtils 原理-反射 apache的PropertyUtils

icetea916的博客 1451

ch32v103xx 烧写

烧写方式 串口uart, usb,swd(wch link)但不建议按此使用,参官方说明。

qq_39239990的博客 637

从零构建:如何用MATLAB和SDR硬件搭建你的第一个OFDM卫星通信原型系统

本文详细介绍了如何利用MATLAB和SDR硬件从零构建OFDM卫星通信原型系统。通过核心组件选型、开发环境配置、OFDM算法实现到系统集成与优化的完整流程,帮助通信工程学生和DIY爱好者快速掌握软件无线电技术在卫星通信中的应用。特别推荐使用HackRF One和MATLAB工具箱实现高性价比的OFDM系统验证。

pz890123456的博客 378

BeanCopier、BeanUtils 对象属性拷贝

开发为了隔离变化,常将 DAO 查询出来的DO和对前端提供的 DTO 隔离开来,它们的结构都是类似的。写很多冗长的b.setFiled(a.getFiled())这样的代码,是繁琐无意义的。于是需要简化对象拷贝方式。大多时候使用的是 Apache 或 Spring 的 BeanUtils,还有另一个更高效的属性拷贝方式:BeanCopier。 一、背景 1️⃣对象拷贝概念 Java,数据类型分为值类型(基本数据类型)和引用类型。对象拷贝分为浅拷贝(浅克隆)与深拷贝(深克隆)。 2️⃣示例前准备。源对象属性

ChineseSoftware的博客 2823

双系统引导修复:GRUB消失后恢复Windows与Ubuntu启动菜单

在UEFI引导架构下,操作系统启动依赖于EFI系统分区(ESP)中存储的引导加载程序。当多个系统共存时,引导管理器负责识别并加载不同操作系统的引导文件。然而,Windows更新或系统调整时常会重置UEFI启动顺序,导致GRUB引导菜单消失,直接进入Windows。这一问题的技术价值在于理解UEFI启动流程与多系统引导管理机制,掌握ESP分区结构与引导文件修复方法。常见的应用场景包括双系统安装后的引导修复、系统更新后的启动项丢失以及磁盘分区调整导致的引导故障。本文针对**GRUB引导菜单消失**和**UEFI

weixin_29895109的博客 294

【Java基础】对象深克隆和浅克隆的原理及实现

彻底理解Java深克隆和浅克隆的原理及实现 Java 面试:对象克隆 如何拷贝对象 深入浅出 Java 中的 clone 克隆方法 java实现克隆的三种(很最全面) 深浅克隆区别 克隆实现方式 深克隆与浅克隆 JAVA clone方法-深复制(深克隆)&浅复制(浅克隆) Java对象克隆——浅克隆和深克隆的区别 Java深克隆和浅克隆的原理及实现 为什么要对象克隆? 克隆的对象可能包含一...

墩墩分墩 2465

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java对象克隆——浅克隆和深克隆的区别

在Java中对象的克隆有深克隆和浅克隆之分。有这种区分的原因是Java中分为基本数据类型和引用数据类型,对于不同的数据类型在内存中的存储的区域是不同的。基本数据类型存储在栈中,引用数据类型存储在堆中。 什么是克隆 克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。 实现克隆有多种方式,可以手工的new出一个新的对象,然后将原来的对象信息一个一个的set到新的对

XXX 2万+

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

java对象的浅克隆和深克隆

引言:   在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷贝一份此属性的引用。首先看一下容易犯的几个小问题 clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是用用户标记实现该接口的类具有某种该接口标记的功能,常见的标记接口有三个:Serializable、Cloneable、R

liyanfeng的博客 195

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java对象的深克隆与浅克隆(对象复制)

假如说你想复制一个简单变量。很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。 但是如果你复制的是一个对象,情况就有些复杂了。 假设说我是一个beginner,我会这样写: class Student { private ...

JavaEdge全是干货的技术号 2578

java对象的深克隆与浅克隆

java编程中,A对象里面有一个引用——B对象。那么我们克隆A对象时,该如何处理B对象?克隆之后的A对象里面的B对象,是一起被克隆了吗?

一天不进步就是退步 578

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

java 对象的克隆一、对象的浅克隆(1)需要克隆类需要重写Object类的clone方法,并且实现Cloneable接口(标识接口,无需实现任何方法)(2)当需要克隆的对象中维护着另外一个引用对象,浅克隆不会克隆另外一个引用对下,而是直接复制维护的另外一个引用对象的地址。(3)对象的浅克隆也不会调用到构造方法。以下为对象的浅克隆的一个例子:package com.clone;import jav...

weixin_35879493的博客 288

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

一、克隆对象从简单的变量克隆入手,就是以下代码 int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。 二、克隆对象从简单的方法入手,就是以下代码 package com.xuecheng.test.freemarker; import org.junit.Test; public class Test001 { @Test

阿鹏 279

java 浅克隆_java对象的浅克隆和深克隆

引言:在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷贝一份此属性的引用。首先看一下容易犯的几个小问题clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是用用户标记实现该接口...

weixin_42365266的博客 123

java字符串深克隆,java对象的浅克隆和深克隆

引言:在Object基类中,有一个方法叫clone,产生一个前期对象的克隆,克隆对象是原对象的拷贝,由于引用类型的存在,有深克隆和浅克隆之分,若克隆对象中存在引用类型的属性,深克隆会将此属性完全拷贝一份,而浅克隆仅仅是拷贝一份此属性的引用。首先看一下容易犯的几个小问题clone方法是Object类的,并不是Cloneable接口的,Cloneable只是一个标记接口,标记接口是用用户标记实现该接口...

weixin_30015371的博客 521

java对象克隆的例子,Java对象之深克隆和浅克隆

**浅克隆:** 只copy对象引用,不copy对象本身。即对象地址不变,仍然只存在一个对象。例如: `User user1 = new User; User user2 = user1;`这里引用类型对象地址不变,只是将user2的引用指向user1的地址。浅克隆代码示例:Bean:public class User {private Integer id;private String name...

weixin_36352023的博客 200

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

java 对象的克隆一、对象的浅克隆(1)需要克隆类需要重写Object类的clone方法,并且实现Cloneable接口(标识接口,无需实现任何方法)(2)当需要克隆的对象中维护着另外一个引用对象,浅克隆不会克隆另外一个引用对下,而是直接复制维护的另外一个引用对象的地址。(3)对象的浅克隆也不会调用到构造方法。以下为对象的浅克隆的一个例子:package com.clone;import jav...

weixin_30994645的博客 76
上一篇: 揭开Java IO流中的flush()的神秘面纱
下一篇: 详解HttpURLConnection(注意末尾的部分)
caomiao2006
博客等级 码龄18年 522粉丝 79原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值