当前位置: 首页 > news >正文

浅拷贝和深拷贝(Java 与 JavaScript)

 一、Java 浅拷贝和深拷贝

在Java中,浅拷贝和深拷贝的主要区别在于对对象的引用和内容的复制方式。

浅拷贝

        Java 的类型有基本数据类型和引用类型,基本数据类型是可以由 CPU 直接操作的类型,无论是深拷贝还是浅拷贝,都是会复制出另一份。而引用类型仅仅是一个指针,指向的是这个对象在堆内存中分配的内存。

举例: 

class Address {String city;Address(String city) {this.city = city;}
}class Person implements Cloneable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class ShallowCopyExample {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("New York");Person person1 = new Person("Alice", address);Person person2 = (Person) person1.clone();// 修改 person2 的地址person2.address.city = "Los Angeles";System.out.println(person1.address.city); // 输出: Los Angeles}
}

        浅拷贝:仅仅是将这个指针拷贝了一份出来,只复制对象的引用,两个指针都指向相同的堆内存地址,原始对象和拷贝对象共享相同的内部对象

深拷贝

举例:

class Address {String city;Address(String city) {this.city = city;}// 深拷贝方法public Address deepCopy() {return new Address(this.city);}
}class Person implements Cloneable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person cloned = (Person) super.clone();cloned.address = this.address.deepCopy(); // 深拷贝地址return cloned;}
}public class DeepCopyExample {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("New York");Person person1 = new Person("Alice", address);Person person2 = (Person) person1.clone();// 修改 person2 的地址person2.address.city = "Los Angeles";System.out.println(person1.address.city); // 输出: New York}
}

        深拷贝:拷贝的就不仅仅是一个指针,还会在堆内存中将原来的对象也拷贝出来一份,原始对象和拷贝对象之间完全独立

        需要注意的一点是:多线程中使用浅拷贝时,多个线程可能会同时修改共享的内部对象,导致数据不一致。这种情况需要通过同步机制(如 synchronized)来避免数据冲突。

当然,深拷贝还常常使用序列化的方式来实现:

import java.io.*;// 可序列化的类
class Address implements Serializable {String city;Address(String city) {this.city = city;}
}class Person implements Serializable {String name;Address address;Person(String name, Address address) {this.name = name;this.address = address;}// 深拷贝方法public Person deepCopy() throws IOException, ClassNotFoundException {// 写入到字节流ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);// 从字节流中读取出对象ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return (Person) ois.readObject();}
}public class SerializationDeepCopyExample {public static void main(String[] args) throws IOException, ClassNotFoundException {Address address = new Address("New York");Person person1 = new Person("Alice", address);Person person2 = person1.deepCopy();// 修改 person2 的地址person2.address.city = "Los Angeles";System.out.println(person1.address.city); // 输出: New York}
}

或者单独抽象出一个方法出来实现: 

/***  序列化实现深拷贝:*  这个方法首先将original对象序列化到一个ByteArrayOutputStream中,然后立即使用ByteArrayInputStream从这个字节流中反序列化对象,*  从而得到一个完全独立的深拷贝。这种方法的优点是它相对简单,且能自动处理对象图中的所有复杂关系。然而,它可能比直接使用拷贝构造函数或者克隆方法更慢,*  且只有实现了Serializable接口的对象才能被复制。*/public class DeepCopyViaSerialization {// 实现深拷贝的方法public static <T> T deepCopy ( T original ) {T copied = null;try {// 创建一个字节流ByteArrayOutputStream bos = new ByteArrayOutputStream();// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {oos.writeObject(original);}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()))) {copied = (T) ois.readObject();}} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}return copied;}
}

 

二、JavaScript 浅拷贝和深拷贝

在JavaScript中,浅拷贝和深拷贝是两种复制对象的方式。

浅拷贝

浅拷贝只复制对象的第一层属性,若属性是引用类型(如对象、数组),则复制的是引用。常用方法包括:

  1. Object.assign()

    // Object.assign 缺点: 仅能实现浅拷贝,不适用于深层嵌套对象
    const obj1 = { a: 1, b: { c: 2 } };
    const shallowCopy = Object.assign({}, obj1);
    shallowCopy.b.c = 3;
    console.log(obj1.b.c); // 输出: 3
  2. 扩展运算符

    const obj1 = { a: 1, b: { c: 2 } };
    // 展开运算符(Spread Operator)是 JavaScript 中的一种语法,用于将可迭代对象(如数组或字符串)展开为独立的元素。它使用三个连续的点号(...)作为操作符。
    // 展开运算符可以在多种情况下使用,包括数组、对象和函数调用等。
    const shallowCopy = { ...obj1 };
    shallowCopy.b.c = 3;
    console.log(obj1.b.c); // 输出: 3

深拷贝

深拷贝会递归复制对象及其所有嵌套的属性,确保新对象与原对象完全独立。常用方法包括:

  1. JSON.stringify() 和 JSON.parse()

    const obj1 = { a: 1, b: { c: 2 } };
    const deepCopy = JSON.parse(JSON.stringify(obj1));
    deepCopy.b.c = 3;
    console.log(obj1.b.c); // 输出: 2
  2. 递归函数

    function deepClone(obj) {if (obj === null || typeof obj !== 'object') return obj;const copy = Array.isArray(obj) ? [] : {};for (let key in obj) {copy[key] = deepClone(obj[key]);}return copy;
    }

在JavaScript中,使用浅拷贝和深拷贝的场景各有不同:

使用浅拷贝的场景

  1. 简单数据复制:当对象只包含基本数据类型(如字符串、数字等),可以使用浅拷贝。

    const original = { a: 1, b: 2 }; const copy = { ...original };
  2. 组件状态管理:在React等框架中,更新状态时使用浅拷贝来保持性能。

    setState(prevState => ({ ...prevState, newProp: value }));
  3. 合并对象:合并多个对象时,浅拷贝可以快速实现。

    const merged = Object.assign({}, obj1, obj2);

使用深拷贝的场景

  1. 复杂对象处理:当对象包含嵌套的引用类型,需要独立复制时。

    const deepCopy = JSON.parse(JSON.stringify(complexObj));
  2. 状态管理:在Redux等状态管理库中,深拷贝可以防止状态不小心被修改。

    const newState = deepClone(state);
  3. 数据处理:在处理API返回的复杂数据结构时,确保原始数据不被改变。

    const processedData = deepClone(apiResponse);

总结:

  • 浅拷贝 适合简单对象和性能优化场景。
  • 深拷贝 用于复杂数据结构,确保数据完整性和独立性。

三、总结

  • 浅拷贝:复制对象的引用,对于引用类型的属性会共享内存。
  • 深拷贝:递归复制对象,确保独立性,常用于需要完整复制对象及其嵌套属性的场景。

相关文章:

浅拷贝和深拷贝(Java 与 JavaScript)

一、Java 浅拷贝和深拷贝 在Java中&#xff0c;浅拷贝和深拷贝的主要区别在于对对象的引用和内容的复制方式。 浅拷贝 Java 的类型有基本数据类型和引用类型&#xff0c;基本数据类型是可以由 CPU 直接操作的类型&#xff0c;无论是深拷贝还是浅拷贝&#xff0c;都是会复制出…...

力扣每日一题 2306.公司命名

做题过程中使用到的java语法&#xff1a; 1.从一个字符串中取出一部分字符串&#xff1a; String str "Hello, World!"; String part str.substring(7); // 从索引7开始到字符串末尾 System.out.println(part); // 输出: World! class Solution { public lo…...

HTML-DOM模型

1.DOM模型 window对象下的document对象就是DOM模型。 DOM描绘了一个层次化的节点树&#xff0c;每一个节点就是一个html标签&#xff0c;而且每一个节点也是一个DOM对象。 2.操作DOM 2.1.获取DOM对象常用方法 获取DOM对象的常用方法有如下几种&#xff1a; getElementById(…...

vue项目报错: At least one is required in a single file component.的主要原因及解决办法

本篇文章主要讲解 vue项目报错&#xff1a; At least one is required in a single file component.的主要原因及解决办法 作者&#xff1a;任聪聪 日期&#xff1a;2024年9月25日 报文信息&#xff1a; Compiled with problems: ERROR in ./src/xxxx.vue Module Error (from …...

03DSP学习-利用syscfg配置IO

上一篇博客介绍了syscfg&#xff0c;对syscfg有了初步的了解&#xff0c;但是在真正使用上它之前&#xff0c;还不能理解他是一个神器。 (在写博客的时候&#xff0c;我是在从头到尾重新完成这个步骤&#xff0c;希望对初学者有点帮助) 找到Board Component 打开syscfg文件&…...

web - RequestResponse

##Request&Response 1&#xff0c;Request和Response的概述 Request是请求对象&#xff0c;Response是响应对象。这两个对象在我们使用Servlet的时候有看到&#xff1a; 此时&#xff0c;我们就需要思考一个问题request和response这两个参数的作用是什么? request:获取请…...

个人文章汇总

文章模块文章汇总心得&资料 真正优秀的人&#xff0c;更懂得尊重别人 如何用沟通解决80%的工作问题 一个IT青年北漂四年的感悟 史上最污技术解读 操作系统相关 操作系统基础 操作系统&#xff1a;从工厂的角度来理解进程线程操作系统&#xff1a;详述对进程和线程的认识操作…...

Java | Leetcode Java题解之第436题寻找右区间

题目&#xff1a; 题解&#xff1a; class Solution {public int[] findRightInterval(int[][] intervals) {int n intervals.length;int[][] startIntervals new int[n][2];int[][] endIntervals new int[n][2];for (int i 0; i < n; i) {startIntervals[i][0] inter…...

大模型智能体在金融公告理解领域的应用 | OPENAIGC开发者大赛高校组AI创新之星奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…...

链表入门(LeetCode题目)

来源&#xff1a;左程云算法 链表的题目我们经常是有思路但是实现起来总有些小问题&#xff0c;所以是准备笔试应多加练习的一类题 206. 反转链表 这道题我们可以新开链表来存&#xff0c;但是如果面试中有这道题&#xff0c;面试官让你优化又该如何呢&#xff1f;所以我们采…...

kibana开启访问登录认证

编辑es配置文件&#xff0c;添加以下内容开启es认证 vim /etc/elasticsearch/elasticsearch.yml http.cors.enabled: true http.cors.allow-origin: "*" http.cors.allow-headers: Authorization xpack.security.enabled: true xpack.security.transport.ssl.enable…...

Java 14Java 15新特性概述

一、Java 14 发布于2020年3月17日。Java 14主要新特性如下&#xff1a; JEP 305&#xff1a;Pattern Matching for instanceof (Preview)instanceof 的模式匹配&#xff08;预览&#xff09; JEP 358&#xff1a;Helpful NullPointerExceptions 有用的 NullPointerExceptions…...

流量特征随机ua修改

作为一个蓝队吗喽&#xff0c;总是能看见因为ua头特征而直接被拦截的ip,当然了还有些是通过X-Forwarded-For被拦截的(X-Forwarded-For:fofa.info&#xff0c;不拦你才怪)&#xff0c; 主要是通过python的mitmproxy和fake_useragent两个模块进行实现&#xff0c;代码量极低 fr…...

CSP-S 2024 提高级 第一轮(初赛) 阅读程序(3)

【题目】 CSP-S 2024 提高级 第一轮&#xff08;初赛&#xff09; 阅读程序&#xff08;3&#xff09; 1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn 1000000 5; 7 const int P1 998…...

如何在 Rust 中通过 Rumqttc 实现 MQTT 通信

Rust 简介 Rust 是一门系统级编程语言&#xff0c;以其卓越的性能、并发能力以及内存安全特性著称。Rust 由 Mozilla 推出&#xff0c;目标是在现代软件开发中提供一种安全高效的编程语言。其设计旨在提供安全、并发和高效的编程体验&#xff0c;同时保持开发效率和代码质量不…...

广东高校建设AIGC实验室时需要注意哪几个关键点?

随着人工智能技术的飞速发展&#xff0c;特别是生成式人工智能&#xff08;AIGC&#xff09;在各行各业中的广泛应用&#xff0c;它已经成为推动新一轮科技革命和产业变革的关键力量。教育部等相关部门近年来也高度重视人工智能领域的人才培养工作&#xff0c;强调要加快推动高…...

设计模式-PIMPL 模式

PIMPL&#xff08;Pointer to IMPLementation&#xff09;&#xff0c;又称Opaque Pointer模式或编译防火墙&#xff0c;是一种在C中广泛应用的编程技术。其核心思想是将类的实现细节从公共接口中分离出来&#xff0c;通过指向实现类的指针来访问类的具体功能。这种模式在提高代…...

Docker部署MongoDB教程

嘿&#xff0c;大家好&#xff01;今天我在三丰云免费服务器上进行了一次激动人心的MongoDB部署测试。这款免费云服务器1核CPU、1G内存、10G硬盘、5M带宽&#xff0c;是不错的免费服务器选择。 首先&#xff0c;让我们简要介绍一下使用到的Docker和MongoDB软件。Docker是一个开…...

堆排序易错点

1.建堆和调整堆&#xff08;插入和删除&#xff09; 建堆和调整堆的过程是不一样的&#xff1a; 建堆 从非终端节点编号的结点开始依次建立大根堆&#xff0c;例如: 拿第2个图说&#xff0c;首先比较-1&#xff0c;7&#xff0c;从中选一个小的&#xff0c;即“-1”&#xf…...

安卓13长按电源按键直接关机 andriod13不显示关机对话框直接关机

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 有些设备需要在长按电源键的时候,直接关机。不需要弹出对话框进行询问。 2.问题分析 过滤电源按键,需要在系统里面处理的话,那么我们需要熟悉android的事件分发,然后再…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

云计算——弹性云计算器(ECS)

弹性云服务器&#xff1a;ECS 概述 云计算重构了ICT系统&#xff0c;云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台&#xff0c;包含如下主要概念。 ECS&#xff08;Elastic Cloud Server&#xff09;&#xff1a;即弹性云服务器&#xff0c;是云计算…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...