【某大厂一面】java深拷贝和浅拷贝的区别

在 Java 中,深拷贝浅拷贝的主要区别在于对象的复制方式和对象中引用类型的处理。下面是更详细的解释,其中也会有相应的代码说明:

1. 浅拷贝(Shallow Copy)

浅拷贝是指复制一个对象时,复制的是对象的“结构”,但对于对象内部的引用类型的成员变量,它们的引用地址并不会被复制,而是共享同一引用。换句话说,浅拷贝只是创建了一个新的对象,但如果该对象内部含有引用类型的成员变量,这些成员变量还是指向原始对象中的相同内存地址。

浅拷贝的特点
  • 浅拷贝复制了对象本身,但并没有复制对象的引用类型成员。
  • 对于引用类型字段(如数组、集合、对象),它们的引用会被共享。
浅拷贝的实现方式
  1. 通过 clone() 方法:Java 的 Object 类提供了 clone() 方法来实现浅拷贝。
  2. 通过 copy() 方法:如果是 ArrayList 等集合类型,可以使用 ArrayListclone() 方法进行浅拷贝。
示例:
import java.util.ArrayList;

class Person implements Cloneable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    // 重写 clone 方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();  // 浅拷贝
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', hobbies=" + hobbies + "}";
    }
}

public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);
        Person person2 = (Person) person1.clone(); // 浅拷贝

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming, Cooking]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

在这个示例中,person1person2hobbies 共享同一个引用,因此修改 person2 中的 hobbies 也会影响到 person1 中的 hobbies

2. 深拷贝(Deep Copy)

深拷贝是指复制一个对象及其内部的所有对象,包括所有引用类型的字段,确保它们有独立的内存空间。换句话说,深拷贝不仅复制了对象本身,还递归地复制对象中包含的每个引用类型的成员变量。这样,原对象和新对象之间就完全独立了,它们不会共享任何引用。

深拷贝的特点
  • 深拷贝会创建一个新的对象,并且递归地复制对象中引用类型的所有成员变量。
  • 原始对象和新对象完全独立,修改新对象不会影响原始对象。
深拷贝的实现方式
  1. 手动实现深拷贝:通过逐个复制对象中的引用类型成员变量来实现。
  2. 通过序列化和反序列化:可以利用 Java 的序列化机制来实现深拷贝,这种方式适用于对象较复杂的情况。
  3. 通过 clone() 方法的深度实现:需要在 clone() 方法中递归地克隆对象中的引用类型字段。
示例:
import java.util.ArrayList;

class Person implements Cloneable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    // 实现深拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone(); // 浅拷贝
        // 进行深拷贝,创建一个新的 hobbies 列表
        cloned.hobbies = new ArrayList<>(this.hobbies);  // 深拷贝
        return cloned;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', hobbies=" + hobbies + "}";
    }
}

public class DeepCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);
        Person person2 = (Person) person1.clone(); // 深拷贝

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

在这个示例中,person1person2hobbies 列表是独立的,因此修改 person2hobbies 不会影响 person1

3. 使用序列化实现深拷贝(通过反序列化)

使用序列化和反序列化可以方便地进行深拷贝,前提是对象及其成员变量都需要实现 Serializable 接口。

示例(通过序列化实现深拷贝):
import java.io.*;

class Person implements Serializable {
    String name;
    ArrayList<String> hobbies;

    public Person(String name, ArrayList<String> hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', hobbies=" + hobbies + "}";
    }
}

public class DeepCopyBySerialization {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ArrayList<String> hobbies = new ArrayList<>();
        hobbies.add("Reading");
        hobbies.add("Swimming");

        Person person1 = new Person("John", hobbies);

        // 深拷贝:序列化 -> 反序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(person1);
        out.flush();
        byte[] byteData = bos.toByteArray();

        ByteArrayInputStream bis = new ByteArrayInputStream(byteData);
        ObjectInputStream in = new ObjectInputStream(bis);
        Person person2 = (Person) in.readObject();

        // 修改 person2 的 hobbies
        person2.hobbies.add("Cooking");

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
    }
}

输出:

person1: Person{name='John', hobbies=[Reading, Swimming]}
person2: Person{name='John', hobbies=[Reading, Swimming, Cooking]}

4. 总结

  • 浅拷贝:复制对象本身,但嵌套对象或引用类型的字段引用仍然指向原对象,即对象的引用被共享。
  • 深拷贝:不仅复制对象本身,还递归地复制所有引用类型的字段,确保原对象和新对象完全独立。

对于简单的对象,使用 clone() 方法实现浅拷贝即可。对于复杂的对象,或者需要独立对象时,可以手动实现深拷贝,或者使用序列化方式。

小伙伴们在开发的过程中有更好的代码实现或者具体的使用场景吗,欢迎大家在评论区进行讨论

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python设计模式 - 组合模式

定义 组合模式&#xff08;Composite Pattern&#xff09; 是一种结构型设计模式&#xff0c;主要意图是将对象组织成树形结构以表示"部分-整体"的层次结构。这种模式能够使客户端统一对待单个对象和组合对象&#xff0c;从而简化了客户端代码。 组合模式有透明组合…

19.Word:小马-校园科技文化节❗【36】

目录 题目​ NO1.2.3 NO4.5.6 NO7.8.9 NO10.11.12索引 题目 NO1.2.3 布局→纸张大小→页边距&#xff1a;上下左右插入→封面&#xff1a;镶边→将文档开头的“黑客技术”文本移入到封面的“标题”控件中&#xff0c;删除其他控件 NO4.5.6 标题→原文原文→标题 正文→手…

一文讲解Java中Object类常用的方法

在Java中&#xff0c;经常提到一个词“万物皆对象”&#xff0c;其中的“万物”指的是Java中的所有类&#xff0c;而这些类都是Object类的子类&#xff1b; Object主要提供了11个方法&#xff0c;大致可以分为六类&#xff1a; 对象比较&#xff1a; public native int has…

多项日常使用测试,带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude

多项日常使用测试&#xff0c;带你了解如何选择AI工具 Deepseek VS ChatGpt VS Claude 注&#xff1a;因为考虑到绝大部分人的使用&#xff0c;我这里所用的模型均为免费模型。官方可访问的。ChatGPT这里用的是4o Ai对话&#xff0c;编程一直以来都是人们所讨论的话题。Ai的出现…

Linux下学【MySQL】表的必备操作( 配实操图和SQL语句)

绪论​ “Patience is key in life &#xff08;耐心是生活的关键&#xff09;”。本章是MySQL中非常重要且基础的知识----对表的操作。再数据库中表是存储数据的容器&#xff0c;我们通过将数据填写在表中&#xff0c;从而再从表中拿取出来使用&#xff0c;本章主要讲到表的增…

【Java数据结构】了解排序相关算法

基数排序 基数排序是桶排序的扩展&#xff0c;本质是将整数按位切割成不同的数字&#xff0c;然后按每个位数分别比较最后比一位较下来的顺序就是所有数的大小顺序。 先对数组中每个数的个位比大小排序然后按照队列先进先出的顺序分别拿出数据再将拿出的数据分别对十位百位千位…

【全栈】SprintBoot+vue3迷你商城(9)

【全栈】SprintBootvue3迷你商城&#xff08;9&#xff09; 往期的文章都在这里啦&#xff0c;大家有兴趣可以看一下 后端部分&#xff1a; 【全栈】SprintBootvue3迷你商城&#xff08;1&#xff09; 【全栈】SprintBootvue3迷你商城&#xff08;2&#xff09; 【全栈】Spr…

php-phar打包避坑指南2025

有很多php脚本工具都是打包成phar形式&#xff0c;使用起来就很方便&#xff0c;那么如何自己做一个呢&#xff1f;也找了很多文档&#xff0c;也遇到很多坑&#xff0c;这里就来总结一下 phar安装 现在直接装yum php-cli包就有phar文件&#xff0c;很方便 可通过phar help查看…

【数据结构】_顺序表

目录 1. 概念与结构 1.1 静态顺序表 1.2 动态顺序表 2. 动态顺序表实现 2.1 SeqList.h 2.2 SeqList.c 2.3 Test_SeqList.c 3. 顺序表性能分析 线性表是n个具有相同特性的数据元素的有限序列。 常见的线性表有&#xff1a;顺序表、链表、栈、队列、字符串等&#xff1b…

OPencv3.4.1安装及配置教程

来到GitHub上opencv的项目地址 https://github.com/opencv/opencv/releases/tag/3.4.1 以上资源包都是 OpenCV 3.4.1 版本相关资源&#xff0c;它们的区别如下&#xff1a; (1). opencv-3.4.1-android-sdk.zip&#xff1a;适用于 Android 平台的软件开发工具包&#xff08;SDK…

世上本没有路,只有“场”et“Bravo”

楔子&#xff1a;电气本科“工程电磁场”电气研究生课程“高等电磁场分析”和“电磁兼容”自学”天线“、“通信原理”、“射频电路”、“微波理论”等课程 文章目录 前言零、学习历程一、Maxwells equations1.James Clerk Maxwell2.自由空间中传播的电磁波3.边界条件和有限时域…

ZYNQ-IP-AXI-GPIO

AXI GPIO 可以将 PS 端的一个 AXI 4-Lite 接口转化为 GPIO 接口&#xff0c;并且可以被配置为单端口或双端口&#xff0c;每个通道的位宽可以独立配置。 通过使能三态门可以将端口动态地配置为输入或输出。 AXIGPIO 是 ZYNQ PL 端的一个 IP 核&#xff0c;可以将 AXI-Lite Mas…

20.Word:小谢-病毒知识的科普文章❗【38】

目录 题目​ NO1.2.3文档格式 NO4.5 NO6.7目录/图表目录/书目 NO8.9.10 NO11索引 NO12.13.14 每一步操作完&#xff0c;确定之后记得保存最后所有操作完记得再次删除空行 题目 NO1.2.3文档格式 样式的应用 选中应用段落段落→开始→选择→→检查→应用一个一个应用ctr…

为什么应用程序是特定于操作系统的?[计算机原理]

你把WINDOWS程序复制到MAC上使用&#xff0c;会发现无法运行。你可能会说&#xff0c;MAC是arm处理器&#xff0c;而WINDWOS是X86 处理器。但是在2019年&#xff0c;那时候MAC电脑还全是Intel处理器&#xff0c;在同样的X86芯片上&#xff0c;运行MAC和WINDOWS 程序还是无法互相…

LigerUI在MVC模式下的响应原则

LigerUI是基于jQuery的UI框架&#xff0c;故他也是遵守jQuery的开发模式&#xff0c;但是也具有其特色的侦听函数&#xff0c;那么当LigerUI作为View层的时候&#xff0c;他所发送后端的必然是表单的数据&#xff0c;在此我们以俩个div为例&#xff1a; {Layout "~/View…

BurpSuite--暴力破解

一.弱口令 1. 基本概念 介绍&#xff1a;弱口令&#xff08;weak password&#xff09;是指那些容易被他人猜测或通过工具破解的密码。虽然弱口令没有严格的定义&#xff0c;但通常它指的是由简单的数字、字母、常用词语或规律性组合构成的密码。 特点&#xff1a; 密码容易被…

深入探讨防抖函数中的 this 上下文

深入剖析防抖函数中的 this 上下文 最近我在研究防抖函数实现的时候&#xff0c;发现一个耗费脑子的问题&#xff0c;出现了令我困惑的问题。接下来&#xff0c;我将通过代码示例&#xff0c;深入探究这些现象背后的原理。 示例代码 function debounce(fn, delay) {let time…

【PostgreSQL内核学习 —— (WindowAgg(一))】

WindowAgg 窗口函数介绍WindowAgg理论层面源码层面WindowObjectData 结构体WindowStatePerFuncData 结构体WindowStatePerAggData 结构体eval_windowaggregates 函数update_frameheadpos 函数 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊…

RocketMQ消息是如何存储的?

大家好&#xff0c;我是锋哥。今天分享关于【RocketMQ消息是如何存储的&#xff1f;】面试题。希望对大家有帮助&#xff1b; RocketMQ消息是如何存储的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RocketMQ 使用了一个高性能、分布式的消息存储架构…

MongoDB平替数据库对比

背景 项目一直是与实时在线监测相关&#xff0c;特点数据量大&#xff0c;读写操作大&#xff0c;所以选用的是MongoDB。但按趋势来讲&#xff0c;需要有一款国产数据库可替代&#xff0c;实现信创要求。选型对比如下 1. IoTDB 这款是由清华大学主导的开源时序数据库&#x…