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.


RDM协议控制端实战:从数据包构造到高效设备发现算法 本文深入探讨了RDM协议控制端的核心开发流程,涵盖从数据包构造、发送到响应解析的全过程。重点解析了如何利用二分搜寻算法高效实现网络设备发现,并分享了组包、解包中的关键代码实现与常见调试技巧,为舞台灯光与智能硬件领域的嵌入式开发提供实战指导。 阅读详情

相关推荐

ZYNQ烧写程序到flash

1.打开SDK创建FBSl项目 点击finish 2.创建BootImage 导入fsbl.elf、.bin、.elf三个文件,Create Image 生成BOOT.bin文件 3.将BOOT文件烧录到FLASH image File选择2中生成的BOOT.bin文件,FSBL File选择fsbl.elf文件,连接好ZYNQ的Jtag,点击Program,即可烧录。 4.烧录程序到FLASH失败 如果是第一次烧录,需更改创建的fsbl工程下的main函数,在如下代码处加入BootModeRegi

qq_40603614的博客 8330

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

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

一个人的江湖 2306

程序员实战:DINOv3 权重文件下载与本地化部署全流程指南

Meta开源的DINOv3视觉大模型凭借70亿参数和17亿图像训练,在语义分割、目标检测等任务表现优异。本文详解预训练权重的获取渠道、校验方法和加载实践。开发者可通过HuggingFace或GitHub获取不同版本权重,包括针对服务器端的ViT系列和边缘设备的ConvNeXt系列。文章提供MD5校验代码确保文件完整性,并给出PyTorch和Transformers两种加载方式。特别强调7B模型需16GB GPU内存,建议根据硬件条件选择合适版本,如边缘设备使用ConvNeXt-Tiny。最后指出DINOv3

xiugou3365的博客 5906

对象拷贝之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

基于Codex平台与AI Agent技能开发,实现抖音爆款视频分析与脚本自动生成

大家好,我是专注于AI应用开发的技术博主。最近在探索如何利用AI工具自动化内容创作时,我发现了一个非常有趣的组合:通过Codex平台创建自定义的Skill(技能),来批量分析抖音平台的爆款视频,并基于分析结果自动生成新的带货视频脚本。这听起来像是内容团队的“黑科技”,但实现起来其实有清晰的路径可循。本文将为你完整拆解这个实战项目,从环境搭建、Skill编写、数据抓取到视频脚本生成,手把手教你打造自己的“AI内容助理”。无论你是想了解AI Agent的开发,还是对短视频自动化创作感兴趣,都能从本文中获得可直接

weixin_34110749的博客 644

基于卷积神经网络CNN实现电力负荷多变量时序预测(PyTorch版)

随着智能电网的发展,精准的电力负荷预测对能源调度和电网稳定具有重要意义。本文基于PyTorch框架,提出一种基于卷积神经网络(CNN)的多变量时间序列预测模型,用于电力负荷的短期预测。

时序笔记 988

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

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

qq_70095877的博客 1627

【部署优化篇三】《DeepSeek边缘计算实战:把目标检测模型塞进树莓派,让AI在巴掌大的设备上“开天眼“》

谁说只有超级计算机才能跑AI?今天咱们就要在树莓派上玩转DeepSeek目标检测,让这个巴掌大的小盒子变成会‘看’世界的智能终端!本文手把手教你从零开始,把最潮的目标检测模型塞进树莓派。全程高能预警,建议准备好你的树莓派4B/5和散热风扇,咱们这就开启边缘计算的魔法之旅!

商务合作|问题讨论|交流学习 请联系作者微信,加微信请务必注明来意,博客主页有联系方式 1306

使用BeanCopier工具类拷贝JavaBean

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

icetea916的博客 1451

CloudCompare 二次开发(17)——点云添加均匀分布的随机噪声

使用CloudCompare编程实现点云添加随机噪声。

点云侠的博客 840

23、电器元件符号及封装大全(2025版本)

总计28类电器元件符号和封装。

XU157303764的博客 2656

BeanCopier、BeanUtils 对象属性拷贝

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

ChineseSoftware的博客 2823

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

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

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

墩墩分墩 2465

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

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

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

XXX 2万+

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

java对象的浅克隆和深克隆

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

liyanfeng的博客 195

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、付费专栏及课程。

余额充值