【轻松拿捏】java中为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?

java中为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?

一、如何在Java中实现对象克隆

1.1 浅拷贝

1.2 深拷贝

1.3 区别总结

二、面试回答技巧

1. 定义克隆及其用途

2. 解释浅拷贝和深拷贝

3. 具体实现浅拷贝和深拷贝

浅拷贝示例:

深拷贝示例:

4. 举例说明

5. 总结


🎈边走、边悟🎈迟早会好

在Java中,使用克隆的原因与其他编程语言类似,主要包括以下几点:

  1. 避免修改原对象:在需要修改对象但又不希望改变原对象时,通过克隆可以操作副本而不影响原对象。
  2. 节省时间和资源:创建一个新对象的代价较高时,克隆可以节省时间和资源。
  3. 实现历史记录和回滚:保存对象的克隆可以实现历史记录和回滚功能。

一、如何在Java中实现对象克隆

        在Java中,对象克隆主要通过实现 Cloneable 接口并覆盖clone() 方法来实现。Java中的克隆也有浅拷贝深拷贝两种方式。

1.1 浅拷贝

        浅拷贝创建一个新对象,但只复制对象的引用而不复制实际的对象数据。也就是说,浅拷贝的对象和原对象共享引用类型的成员变量。

实现浅拷贝的方式:

  1. 实现 Cloneable 接口。
  2. 覆盖 clone() 方法。
class Person implements Cloneable {String name;int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 调用 Object 类的 clone 方法}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + '}';}
}public class Main {public static void main(String[] args) {try {Person p1 = new Person("Alice", 30);Person p2 = (Person) p1.clone();p2.name = "Bob";System.out.println(p1); // Person{name='Alice', age=30}System.out.println(p2); // Person{name='Bob', age=30}} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

在这个例子中,p1p2 是两个不同的对象,但它们的引用类型成员变量共享同一个引用

1.2 深拷贝

        深拷贝不仅复制对象本身,还递归复制对象内部所有引用的对象。因此,深拷贝的对象与原对象完全独立。

实现深拷贝的方式:

  1. 手动复制所有嵌套对象。
  2. 如果对象较复杂,可以使用序列化和反序列化来实现深拷贝。

手动深拷贝:

class Address implements Cloneable {String city;public Address(String city) {this.city = city;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Address{city='" + city + "'}";}
}class Person implements Cloneable {String name;int age;Address address;public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}@Overrideprotected Object clone() throws CloneNotSupportedException {Person cloned = (Person) super.clone();cloned.address = (Address) address.clone(); // 深拷贝地址return cloned;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + ", address=" + address + '}';}
}public class Main {public static void main(String[] args) {try {Address address = new Address("New York");Person p1 = new Person("Alice", 30, address);Person p2 = (Person) p1.clone();p2.name = "Bob";p2.address.city = "Los Angeles";System.out.println(p1); // Person{name='Alice', age=30, address=Address{city='New York'}}System.out.println(p2); // Person{name='Bob', age=30, address=Address{city='Los Angeles'}}} catch (CloneNotSupportedException e) {e.printStackTrace();}}
}

在这个例子中,p2p1 的深拷贝,修改 p2 的地址不会影响 p1 的地址

1.3 区别总结

  • 浅拷贝:只复制对象本身及其基本类型成员变量,引用类型成员变量仍然指向原对象的引用
  • 深拷贝:递归复制对象及其所有层次的成员变量,创建完全独立的新对象

        选择使用哪种拷贝方式取决于具体需求和对象的复杂性。在需要完全独立的副本时,使用深拷贝;在只需要复制表层结构时,使用浅拷贝。

二、面试回答技巧

        在面试中回答有关对象克隆的问题时,以下是一些技巧和结构化的回答方法,可以帮助你清晰、完整地展示你的知识和理解。

1. 定义克隆及其用途

        示例回答: “对象克隆是创建对象副本的过程,主要用于在不影响原对象的情况下进行修改、节省资源、以及实现历史记录和回滚功能。例如,当创建一个新对象的成本较高时,克隆可以快速生成一个相同的对象。”

2. 解释浅拷贝和深拷贝

        示例回答: “在Java中,克隆分为浅拷贝和深拷贝。浅拷贝只复制对象的基本类型成员变量和引用类型成员变量的引用,而不复制实际对象的数据。深拷贝则递归复制所有层次的对象,确保新对象与原对象完全独立。”

3. 具体实现浅拷贝和深拷贝

        示例回答: “浅拷贝通过实现 Cloneable 接口并覆盖 clone() 方法实现。调用 super.clone() 可以创建对象的浅拷贝。深拷贝需要手动复制所有嵌套对象,或者使用序列化和反序列化来实现递归复制。”

浅拷贝示例:
class Person implements Cloneable {String name;int age;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 浅拷贝}
}
深拷贝示例:
class Address implements Cloneable {String city;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 浅拷贝}
}class Person implements Cloneable {String name;int age;Address address;@Overrideprotected Object clone() throws CloneNotSupportedException {Person cloned = (Person) super.clone();cloned.address = (Address) address.clone(); // 深拷贝return cloned;}
}

4. 举例说明

        示例回答: “假设有一个 Person 类,它包含一个 Address 类的引用。使用浅拷贝,改变 Address 对象的属性会影响到原来的 Person 对象。使用深拷贝,每个Person对象都有独立的 Address 副本,修改一个对象不会影响另一个对象。”

5. 总结

        示例回答: “总结来说,浅拷贝适用于简单对象结构,开销较小,但存在引用共享的问题。深拷贝适用于复杂对象结构,保证对象的完全独立,但实现起来更复杂,开销也更大。”

 🌟感谢支持 听忆.-CSDN博客

🎈众口难调🎈从心就好

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

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

相关文章

【Python】使用库 -- 详解

库就是别人已经写好了的代码,可以让我们直接拿来用。 一个编程语言能不能流行起来,一方面取决于语法是否简单方便容易学习,一方面取决于生态是否完备。所谓的 “生态” 指的就是语言是否有足够丰富的库,来应对各种各样的场景。在…

LeetCode 188题: 买卖股票的最佳时机IV优化(原创)

之前完成了LeetCode 188题: 买卖股票的最佳时机IV(原创)-CSDN博客,虽然完成代码编写,并提交成功,但运行效率还未达到最优的1ms,见下图: 仔细检查代码,感觉还是有可优化的…

OpenCV中的GrabCut图像分割算法的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 功能描述 GrabCut 算法是一种用于图像分割的技术,由 Carsten Rother、Vladimir Kolmogorov 和 Andrew Blake 在 2004 年 SIGGRAPH 会议的论文《…

AI多模态识别ALM大模型分享:Qwen-Audio

ALM (Large Audio Language Model) 1)Qwen-Audio 声音音频对话 参考: https://qwen-audio.github.io/Qwen-Audio/ https://huggingface.co/Qwen/Qwen-Audio-Chat “Qwen-Audio 接受多种音频(人类语音、自然声音、音乐和歌曲)以及…

基于面向对象和递归的拦截器设计模式

1 定义 拦截器模式(Interceptor Pattern),是指提供一种通用的扩展机制,可以在业务操作前后提供一些切面的(Cross-Cutting)的操作。这些切面操作通常是和业务无关的,比如日志记录、性能统计、安…

day2 单机并发缓存

文章目录 1 sync.Mutex2 支持并发读写3 主体结构 Group3.1 回调 Getter3.2 Group 的定义3.3 Group 的 Get 方法 4 测试 本文代码地址: https://gitee.com/lymgoforIT/gee-cache/tree/master/day2-single-node 本文是7天用Go从零实现分布式缓存GeeCache的第二篇。 …

【LeetCode】80.删除有序数组中的重复项II

1. 题目 2. 分析 3. 代码 class Solution:def removeDuplicates(self, nums: List[int]) -> int:if len(nums) < 3:return len(nums)i 0j 1k 2while(k < len(nums)):if (nums[i] nums[j]):while(k < len(nums) and nums[j] nums[k] ):k1if (k < len(nums…

校验deb、rpm、apt、yum安装文件完整性测试

简介&#xff1a;deb包在Linux操作系统中类似于windows中的软件包&#xff08;msi&#xff09;&#xff0c;几乎不需要什么复杂的编译即可通过鼠标点击安装使用。此外,deb广泛应用于越狱后iOS软件及MeeGo&#xff08;含Maemo软件&#xff09;中。deb 格式是 Debian 系统(包含 D…

StringBuilder和StringBuffer

目录 &#xff08;一&#xff09;为什么要引入StringBuilder和StringBuffer &#xff08;二&#xff09;StringBuilder和StringBuffer &#xff08;1&#xff09;底层数组长度 (2)StringBuilder与StringBuffer扩容机制 &#xff08;3&#xff09;StringBuilder和StringBuf…

并发编程面试题1

并发编程 1、线程池中提交一个任务的流程是怎样的&#xff1f; 1、提交任务&#xff1a;首先&#xff0c;一个任务被提交到线程池。这个任务通常是一个实现了Runnable或Callable接口的对象&#xff1b; 2、检测线程池状态&#xff1a;线程池会首先检测其运行状态。如果线程池…

javafx使用发现的问题

1.按钮的方法 如果在fxml按钮的方法报错&#xff0c;并且你已在lei中添加了它的按钮及其按钮方法&#xff0c;那么可能是FXML和控制器类未正确关联&#xff1a; 确保你的FXML文件通过 fx:controller 属性正确指定了与之关联的控制器类。例如&#xff0c;fx:controller"c…

数据库之存储引擎

目录 一、MySQL支持的存储引擎 二、查看MySQL默认存储引擎 三、修改MySQL默认存储引擎 四、常用的存储引擎 1.InnoDB 2.MyISAM 3.MEMORY 一、MySQL支持的存储引擎 使用SHOW ENGINES \G; 命令查看 以“\G”结尾&#xff0c;其作用是将查询结果按列显示。 Engine&#xff…

更加深入Mysql-04-MySQL 多表查询与事务的操作

文章目录 多表查询内连接隐式内连接显示内连接 外连接左外连接右外连接 子查询 事务事务隔离级别 多表查询 有时我们不仅需要一个表的数据&#xff0c;数据可能关联到俩个表或者三个表&#xff0c;这时我们就要进行夺标查询了。 数据准备&#xff1a; 创建一个部门表并且插入…

Fiddler 导出请求为curl格式

来自:https://www.cnblogs.com/yudongdong/p/15418181.html Fiddler 下载地址: https://downloads.getfiddler.com/fiddler-classic/FiddlerSetup.5.0.20243.10853-latest.exe 这段代码加到类中 public static RulesOption("关闭请求体转代码", "生成代码&qu…

达梦数据库系列—29. DTS迁移ORACLE到DM

目录 1.ORACLE源端信息 2.DM目的端信息 3.DTS 迁移评估 4.数据库迁移 4.1 Oracle 源端数据库准备 4.2 目的端达梦数据库准备 初始化参数设置 兼容性参数设置 表空间规划 用户规划 创建迁移用户和表空间 4.3迁移步骤 创建迁移 配置数据源 配置迁移对象及策略 开…

django-vue-admin项目运行

文本主要对django-vue-admin项目进行了简要介绍&#xff0c;并且对前后端进行了源码安装和运行。在此基础上可作为管理系统二次开发的基础框架。 一.django-vue-admin简介和安装 1.简介 django-vue-admin项目是基于RBAC模型权限控制的中小型应用的基础开发平台&#xff0c;采…

昇思MindSpore学习总结十六 —— 基于MindSpore的GPT2文本摘要

1、mindnlp 版本要求 !pip install tokenizers0.15.0 -i https://pypi.tuna.tsinghua.edu.cn/simple # 该案例在 mindnlp 0.3.1 版本完成适配&#xff0c;如果发现案例跑不通&#xff0c;可以指定mindnlp版本&#xff0c;执行!pip install mindnlp0.3.1 !pip install mindnlp …

使用Amazon Web Services Lambda把天气预报推送到微信

最近北京开始下雨&#xff0c;开始和同事打赌几点能够雨停&#xff0c;虽然Iphone已经提供了实时天气&#xff0c;但是还是想用国内的API试试看看是不是更加准确些。 以下是我使用的服务&#xff1a; 地图SDK/APP获取 经纬度彩云天气API 通过地理位置获取天气信息Lambda 作为…

关于Mysql的面试题(实时更新中~)

一、主键约束与“not null unique”区别 1、作为Primary Key的域/域组不能为null&#xff0c;而Unique Key可以。 2、在一个表中只能有一个Primary Key&#xff0c;而多个Unique Key可以同时存在。unique not null 可以 将表的一列或多列定义为唯一性属性&#xff0c;而prima…

buu做题(6)

目录 [GWCTF 2019]我有一个数据库 [WUSTCTF2020]朴实无华 [GWCTF 2019]我有一个数据库 什么都没有, 尝试用dirsearch扫一下目录 可以扫到一个 /phpmyadmin 可以直接进入到数据库里面 但里面没什么东西 可以看到它的版本不是最新的, 搜一下相关的漏洞 phpMyAdmin 4.8.1后台文…