java 面试 -- 深拷贝与浅拷贝

一、浅拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身和对象中的基本数据类型,而不拷贝对象中的引用类型。换句话说,对于对象中的引用类型,浅拷贝只是拷贝了引用,而没有拷贝引用的对象。因此,原对象和拷贝后的对象共享同一个引用对象

下面是一个浅拷贝的示例:

public class ShallowCopyExample {  private int value;  private String refValue;  public ShallowCopyExample(int value, String refValue) {  this.value = value;  this.refValue = refValue;  }  // getter 和 setter 省略  @Override  public String toString() {  return "ShallowCopyExample{" +  "value=" + value +  ", refValue='" + refValue + '\'' +  '}';  }  public static void main(String[] args) {  ShallowCopyExample original = new ShallowCopyExample(1, "Original");  ShallowCopyExample copied = new ShallowCopyExample(original.getValue(), original.getRefValue());  System.out.println("Original: " + original);  System.out.println("Copied: " + copied);  copied.setRefValue("Copied");  System.out.println("After modification:");  System.out.println("Original: " + original);  System.out.println("Copied: " + copied);  }  
}

在上面的示例中,我们创建了一个ShallowCopyExample类,它包含一个基本数据类型value和一个引用类型refValue。在main方法中,我们创建了一个原始对象original,并通过浅拷贝创建了一个拷贝对象copied。当我们修改copied对象的refValue属性时,可以发现原始对象original的refValue属性也被修改了,这是因为它们共享同一个引用对象。

二、深拷贝

深拷贝是指拷贝对象时不仅拷贝对象本身和基本数据类型,还递归拷贝对象中的引用类型。也就是说,对于对象中的引用类型,深拷贝会创建一个新的对象,并将原对象中的引用指向新创建的对象。因此,原对象和拷贝后的对象不共享任何引用对象。

在Java中,实现深拷贝通常有两种方法:

1. 使用序列化和反序列化;

通过实现Serializable接口,我们可以将对象转换为字节流,然后再从字节流中恢复出一个新的对象。这个过程会创建对象所有属性的新副本,包括引用类型属性指向的对象。

2. 使用拷贝构造函数和覆写clone方法。

这种方法需要手动编写代码来递归地复制对象的所有属性。需要注意的是,如果对象包含循环引用,这种方法可能会导致无限递归。

对于特定的数据类型,如集合或数组,Java也提供了相关的拷贝方法,如ArrayList的addAll()方法或数组的copyOf()方法。但是这些方法通常只适用于浅拷贝。

三、 深拷贝的工具类

在Java中,实现深拷贝的工具类有很多,包括一些第三方库如Apache Commons Lang和Google Guava,以及Java标准库中的clone()方法和序列化机制。下面是一些常见的深拷贝工具类和方法:

1. Apache Commons Lang的SerializationUtils

Apache Commons Lang库提供了一个名为SerializationUtils的工具类,它可以通过序列化和反序列化来实现对象的深拷贝。使用这种方法的一个优点是它可以处理复杂的对象图,包括循环引用。

import org.apache.commons.lang3.SerializationUtils;  // ...  MyObject original = new MyObject();  
// 设置original对象的属性...  MyObject copied = SerializationUtils.clone(original);

请注意,这种方法要求对象及其所有嵌套对象都实现了Serializable接口。

2. Java的clone()方法和自定义克隆

Java的Object类提供了一个受保护的clone()方法,用于创建并返回此对象的一个拷贝。如果类实现了Cloneable接口,就可以调用此方法。但是,默认的clone()方法实现的是浅拷贝,所以需要在类中覆写此方法来实现深拷贝。

public class MyObject implements Cloneable {  private MyNestedObject nestedObject;  @Override  protected Object clone() throws CloneNotSupportedException {  MyObject obj = (MyObject) super.clone();  obj.nestedObject = (MyNestedObject) this.nestedObject.clone();  return obj;  }  // MyNestedObject类也需要实现clone()方法来进行深拷贝...  
}

3. 使用Java序列化进行深拷贝

另一种利用Java序列化实现深拷贝的方法是手动序列化对象到字节流,然后从字节流中反序列化出一个新的对象。这种方法类似于SerializationUtils,但它是手动实现的。

java
import java.io.*;  public class DeepCopyUtil {  public static <T> T deepCopy(T object) {  try {  // 将对象写入到字节流中  ByteArrayOutputStream bos = new ByteArrayOutputStream();  ObjectOutputStream oos = new ObjectOutputStream(bos);  oos.writeObject(object);  oos.flush();  oos.close();  // 从字节流中恢复对象  ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  ObjectInputStream ois = new ObjectInputStream(bis);  @SuppressWarnings("unchecked")  T copy = (T) ois.readObject();  ois.close();  return copy;  } catch (IOException | ClassNotFoundException e) {  throw new RuntimeException(e);  }  }  
}

4. 使用第三方库如Google Guava

Google Guava库也提供了一些用于深拷贝的工具,但它不像Apache Commons Lang那样直接提供一个通用的深拷贝方法。相反,Guava提供了一些实用程序类和方法,可以帮助你更容易地实现深拷贝逻辑。

在选择深拷贝工具类时,需要考虑对象的复杂性、性能需求、是否支持循环引用以及是否需要额外的库依赖等因素。如果对象的结构相对简单,并且没有循环引用,那么自定义的clone()方法可能就足够了。对于更复杂的场景,使用Apache Commons Lang或Java序列化可能是更好的选择。

三、 常见面试汇总

面试题目1:Object类的clone()方法实现的是深拷贝还是浅拷贝?

Object类的clone()方法实现的是浅拷贝。它只会复制对象的非引用类型属性和引用类型属性的引用,而不会复制引用的对象本身。因此,如果对象包含引用类型属性,那么这些属性在拷贝后仍然指向原始对象中的对象。

要实现深拷贝,通常需要在具体的类中覆写clone()方法,并递归地复制所有引用类型属性指向的对象。

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

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

相关文章

Multi-Thread TCP Server Client

prerequisite knowledge: Basic TCP Server & Client: URL Server #include <stdio.h> #include <string.h> #include <unistd.h> // read and write (TCP); sendto and recvfrom (UDP) #include <arpa/inet.h> // 包含#include <sys/socket.…

Ubuntu如何更换 PyTorch 版本

环境&#xff1a; Ubuntu22.04 WLS2 问题描述&#xff1a; Ubuntu如何更换 PyTorch 版本考虑安装一个为 CUDA 11.5 编译的 PyTorch 版本。如何安装旧版本 解决方案&#xff1a; 决定不升级CUDA版本&#xff0c;而是使用一个与CUDA 11.5兼容的PyTorch版本&#xff0c;您可…

Mac远程桌面windows11

文章目录 一、Mac安装Microsoft Remote Desktop二、Window11打开远程登录权限三、常见问题 一、Mac安装Microsoft Remote Desktop 下载地址&#xff1a;点击这里官方下载 基本不用看&#xff0c;凭感觉用就行。搞不定详情见&#xff1a;官方说明 二、Window11打开远程登录权…

2024年4月个人工作生活总结

本文为 2024年4月工作生活总结。 研发编码 excel创建直方图 因工作需要&#xff0c;在excel学习使用了直方图。下面是文字版。 加载工具库&#xff1a; 直方图可在“数据”->"数据分析"中找到&#xff0c;如无&#xff0c;则要加载之。文件->选项->加载…

c#数据库: 10.调用存储过程查询信息,并显示在窗体上

查询女生信息&#xff0c;并将信息显示在窗体上: 原数据表//右键数据库名,新建查询 ------------- 新建查询窗口,添加新建存储过程Procedure_GetGirls1和查询代码如下 : CREATE PROCEDURE dbo.Procedure_GetGirls1 /*存储过程名称*/ AS SELECT * f…

[React] 手动实现CountTo 数字滚动效果

这个CountTo组件npmjs里当然有大把的依赖存在&#xff0c;不过今天我们不需要借助任何三方依赖&#xff0c;造个轮子来手动实现这个组件。 通过研究其他count to插件我们可以发现&#xff0c;数字滚动效果主要依赖于requestAnimationFrame 通过js帧来让数字动起来&#xff0c;…

【docker】Spring Boot3.x 打包 Docker容器

Docker化Spring Boot应用 创建文件夹 demo mkdir democd demo创建Dockerfile # 两个 openjdk 二选一 #FROM openjdk:17-jre-alpineFROM eclipse-temurin:17MAINTAINER chengxuyuanshitang <chengxuyuanshitangXX.com>RUN mkdir -p /workspace/java/demoCOPY demo.ja…

Python 与 TensorFlow2 生成式 AI(五)

原文&#xff1a;zh.annas-archive.org/md5/d06d282ea0d9c23c57f0ce31225acf76 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十二章&#xff1a;用生成式人工智能玩视频游戏&#xff1a;GAIL 在之前的章节中&#xff0c;我们已经看到如何使用生成式人工智能来生成…

LVGL自定义滑动

触摸和编码器都可以操作 typedef struct {lv_obj_t* obj;int16_t x;int16_t y;int16_t width;int16_t height; }pos_and_size_t;typedef struct {lv_obj_t* obj;lv_coord_t height;lv_coord_t width;lv_coord_t width_pad;lv_coord_t height_pad;lv_coord_t child_widget;lv_co…

Mybatis.net + Mysql

项目文件结构 NuGet下载Mybatis.net相关包&#xff1a;IBatisNet 安装完成后&#xff0c;会显示在&#xff0c;在已安装页面。同时&#xff0c;在管理器中的引用列表中&#xff0c;会多出来两个引用文件 IBatisNet.CommonIBatisNet.DataMapper 安装 Mysql.data。 注意&#xff…

【设计模式】14、strategy 策略模式

文章目录 十四、strategy 策略模式14.1 map_app14.1.1 map_app_test.go14.1.2 map_app.go14.1.3 navigate_strategy.go 十四、strategy 策略模式 https://refactoringguru.cn/design-patterns/strategy 需求: client 知道很多不同的策略, 希望在运行时切换. 场景示例: 就像高…

使用一等对象函数重构策略模式

目录 经典的策略模式 使用函数重构策略模式 选择最佳策略的简单模式

C++ 中 scanf 的高阶用法:scanf(“%[a-z]“,ch);

● C 中 scanf 的高阶用法&#xff1a;scanf("%[a-z]",ch);语句 scanf("%[a-z]",ch); 表示只读入小写字母入字符串。任何包含非小写字母的字符串&#xff0c;将不能读入&#xff0c;自然也不可能有输出。例如&#xff1a; 运行下面代码&#xff1a;输入 ab…

Harbor服务器停电重启后用户不能登陆怎么办?

Harbor服务问题处理 今天遇到一个问题&#xff0c;可能因为这几天下暴雨打雷比较厉害&#xff0c;办公室机房跳闸&#xff0c;有一台测试服务器没有停电保护停机。重启这台服务器以后&#xff0c;上面运行的Harbor服务登陆不上&#xff0c;用户名和密码都没改过&#xff0c;搞…

Stm32CubeMX 为 stm32mp135d 添加网卡 eth

Stm32CubeMX 为 stm32mp135d 添加网卡 eth 一、启用设备1. eth 设备添加2. eth 引脚配置2. eth 时钟配置 二、 生成代码1. optee 配置2. uboot 配置3. linux 配置 bringup 可参考&#xff1a;Stm32CubeMX 生成设备树 一、启用设备 1. eth 设备添加 我这里只启用一个eth设备&…

特斯拉与百度合作;字节正全力追赶AI业务;小红书内测自研大模型

特斯拉中国版 FSD 或与百度合作 根据彭博社的报道&#xff0c;特斯拉将通过于百度公司达成地图和导航协议&#xff0c;扫清在中国推出 FSD 功能的关键障碍。 此前&#xff0c;中国汽车工业协会、国家计算机网络应急技术处理协调中心发布《关于汽车数据处理 4 项安全要求检测情…

【漏洞复现】zookeeper AdminServer 未授权访问漏洞

0x01 产品简介 ZooKeeper 是一个集中式服务&#xff0c;用于维护配置信息、命名、提供分布式同步和提供组服务。ZooKeeper的AdminServer是其管理界面的一部分&#xff0c;通常用于监控ZooKeeper集群的状态和执行一些管理操作。AdminServer提供了Web-based的管理和监控功能&…

大数据中的项目数据采集

Datax介绍 官网&#xff1a; DataX/introduction.md at master alibaba/DataX GitHub DataX 是阿里云 DataWorks数据集成 的开源版本&#xff0c;在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。 DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS…

C#条件运算符

条件运算符分为&#xff1a;&#xff08;比较运算符 判断运算符&#xff09; 条件运算符的作用: 用于比较两个变量或者常量 判断符号: > < ! > < 条件运算符不能直接使用 需要搭配运算符使用 <u>*如果条件满足则返回true 条件不满足则返回fals…