关于Clone

关于Clone

一般情况下,如果使用clone()方法,则需满足以下条件。
1、对任何对象o,都有o.clone() != o。换言之,克隆对象与原型对象不是同一个对象。
2、对任何对象o,都有o.clone().getClass() == o.getClass()。换言之,克隆对象与原型对象的类型一样。
3、如果对象o的equals()方法定义恰当,则o.clone().equals(o)应当成立。

我们在设计自定义类的clone()方法时,应当遵守这3个条件。一般来说,这3个条件中的前2个是必需的,第3个是可选的。

在这里插入图片描述

浅拷贝

super.clone()方法直接从堆内存中以二进制流的方式进行复制,重新分配一个内存块,因此其效率很高。
由于super.clone()方法基于内存复制,因此不会调用对象的构造函数,也就是不需要经历初始化过程。
只有基本类型的参数会被拷贝一份,非基本类型的对象不会被拷贝一份,而是继续使用传递引用的方式,原型对象与克隆对象的该属性只是指向同一对象的引用,即浅拷贝

	@Override
	public Object clone() throws CloneNotSupportedException{
		Employees employees = (Employees)super.clone();
		return employees;
	}

在这里插入图片描述

深拷贝

在日常开发中,使用super.clone()方法并不能满足所有需求。如类中存在引用对象属性。就要需要实现深拷贝,必须要自己手动修改 clone 方法才行。

	@Override
	public Object clone() throws CloneNotSupportedException{
			List<String> temp = new ArrayList<String>();
			for(String s : this.getEmpList()){
				temp.add(s);
			}
			return new Employees(temp);
	}

在这里插入图片描述

使用序列化(Serializable)

不过如果当原型对象维护很多引用属性的时候,手动分配会比较烦琐。因此,在Java中,如果想完成原型对象的深克隆,则通常使用 序列化(Serializable)的方式。

public class Employees implements Cloneable,Serializable{

	private List<String> empList;
	
	public Employees(){
		empList = new ArrayList<String>();
	}
	
	public Employees(List<String> list){
		this.empList=list;
	}
	
	public void loadData(){
		//read all employees from database and put into the list
		empList.add("Pankaj");
		empList.add("Raj");
		empList.add("David");
		empList.add("Lisa");
	}
	
	public List<String> getEmpList() {
		return empList;
	}

	@Override
	public Object clone() throws CloneNotSupportedException{
			List<String> temp = new ArrayList<String>();
			for(String s : this.getEmpList()){
				temp.add(s);
			}
			return new Employees(temp);
	}
	
	public Object deepClone() throws CloneNotSupportedException{
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(bos);
			oos.writeObject(this);
			
			ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
			ObjectInputStream ois = new ObjectInputStream(bis);
			return (Employees)ois.readObject();
			
		} catch (IOException | ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}
	}
}

测试

	public static void main(String[] args) throws CloneNotSupportedException {
		Employees emps = new Employees();
		emps.loadData();

		Employees empsNew = (Employees) emps.deepClone();
		Employees empsNew1 = (Employees) emps.deepClone();
		List<String> list = empsNew.getEmpList();
		list.add("John");
		List<String> list1 = empsNew1.getEmpList();
		list1.remove("Pankaj");
		
		System.out.println("emps List: "+emps.getEmpList());
		System.out.println("empsNew List: "+list);
		System.out.println("empsNew1 List: "+list1);
	}

emps List: [Pankaj, Raj, David, Lisa]
empsNew List: [Pankaj, Raj, David, Lisa, John]
empsNew1 List: [Raj, David, Lisa]

还原克隆破坏单例的事故现场
假设有这样一个场景,如果复制的目标对象恰好是单例对象,那会不会使单例对象被破坏呢?
当然,我们在已知的情况下肯定不会这么干,但如果发生了意外怎么办?不妨来试一下

public class A11_EagerInitializedSingletonClone implements Cloneable {

	private static final A11_EagerInitializedSingletonClone instance = new A11_EagerInitializedSingletonClone();

	// private constructor to avoid client applications to use constructor
	private A11_EagerInitializedSingletonClone() {
	}

	public static A11_EagerInitializedSingletonClone getInstance() {
		return instance;
	}
	
	@Override
	public A11_EagerInitializedSingletonClone clone() throws CloneNotSupportedException{
		A11_EagerInitializedSingletonClone employees = (A11_EagerInitializedSingletonClone)super.clone();
		return employees;
	}
}
A11_EagerInitializedSingletonClone instanceOne = A11_EagerInitializedSingletonClone.getInstance();
A11_EagerInitializedSingletonClone instanceOne2  = instanceOne.clone();
System.out.println(instanceOne==instanceOne2);

结果为false确实创建了两个不同的对象。

实际上防止复制破坏单例对象的解决思路非常简单,禁止复制便可。要么我们的单例类不实现Cloneable接口,要么我们重写clone()方法,在clone()方法中返回单例对象即可,具体代码如下

	@Override
	public A11_EagerInitializedSingletonClone clone() throws CloneNotSupportedException{
		return instance;
	}
A11_EagerInitializedSingletonClone instanceOne = A11_EagerInitializedSingletonClone.getInstance();
A11_EagerInitializedSingletonClone instanceOne2  = instanceOne.clone();
System.out.println(instanceOne==instanceOne2);

结果为true

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

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

相关文章

实景三维技术未来的着力点应该在哪里?

随着社会经济和文化生活的不断发展&#xff0c;公共服务和公共安全就成为政府部门和各行业各部门的一个非常重要的工作&#xff0c;提高政府以及相关部门对紧急事件的快速反应和抗风险能力&#xff0c;建设应急指挥系统为公众提供更便捷的紧急救助服务&#xff0c;已经成为社会…

【GoLang入门教程】Go语言几种标准库介绍(五)

如何解决大模型的「幻觉」问题&#xff1f; 文章目录 如何解决大模型的「幻觉」问题&#xff1f;前言几种库image库 (常见图形格式的访问及生成)关键概念和类型&#xff1a;示例 IO库示例 math库(数学库)常用的函数和常量&#xff1a;示例 总结专栏集锦写在最后 前言 上一篇&a…

计算机毕业设计 | springboot 高校新生报到系统(附源码)

1&#xff0c;绪论 1.1 开发背景 学校新生报到仅仅靠原始的手工管理&#xff0c;面对大量的新生信息&#xff0c;无法有效率地将其中的重要部分提取出来&#xff0c;并做出相应的判断和处理。学校的决策只能依据报表数据&#xff0c;在浪费大量人力、物力的同时无法做到实时监…

图像模板匹配算法(MATLAB)

模板匹配是一种用于在图像中定位和识别对象的技术。它的基本思想是: 提取图像中的一个子图像作为“模板”(template)。这个子图像通常包含我们感兴趣的目标对象。 在整个原始图像上,逐点比较模板和原始图像的相似度。相似度通常用归一化的交叉相关(Normalized Cross Correlati…

Unity | 资源热更(YooAsset AB)

目录 一、AssetBundle 1. 插件AssetBundle Browser 打AB包 &#xff08;1&#xff09;Unity&#xff08;我用的版本是2020.3.8&#xff09;导入AssetBundle Browser &#xff08;2&#xff09;设置Prefab &#xff08;3&#xff09;AssetBundleBrowser面板 2. 代码打AB包…

Unity类银河恶魔城学习记录1-9 PlayerWallSilde源代码 P36

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Player.cs using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; us…

【30秒看懂大数据】数据指标

公众号&#xff1a;知幽科技 PS:本文属专栏第24篇 简单说 数据指标是指对企业经营数据转化为可量化、可衡量、可对比、可预测的一个度量或者维度同称。 举例理解 你在小区门口开了一家馒头店。 开业第一天你算了下一共卖了50个馒头&#xff0c;一共收款100元&#xff0…

通过手写简易版RPC理解RPC原理

RPC是什么 所谓的RPC其实是为了不同主机的两个进程间通信而产生的&#xff0c;通常不同的主机之间的进程通信&#xff0c;程序编写需要考虑到网络通信的功能&#xff0c;这样程序的编写将会变得复杂。RPC就来解决这一问题的&#xff0c;一台主机上的进程对另外一台主机的进程发…

乐意购项目前端开发 #6

一、商品详情页面 代码模版 创建Detail文件夹, 然后创建index.vue文件 <script setup> import { getDetail } from "/api/goods/index"; import { ref, onMounted } from "vue"; import { useRoute } from "vue-router"; import { useCar…

2024/2/3学习记录

微信小程序 小程序中组件的分类 视图容器 view 普通视图区域&#xff0c;类似于 div 常用来实现页面的布局效果。 scroll-view 可滚动的视图区域&#xff0c;常用来实现滚动列表效果 swiper 和 swiper-item 常用 swiper 组件的常用属性 轮播图容器组件和轮播图item组件 基…

【CSS】常见样式总结

一. 溢出隐藏 1.1 单行文本溢出 .content{max-width:200px; /* 定义容器最大宽度 */overflow:hidden; /* 隐藏溢出的内容 */text-overflow:ellipsis; /* 溢出部分...表示 */white-space: nowrap; /* 确保文本在一行内显示 */ }问题&#xff1a;display:flex 和 ellipsis 冲…

Win7 Python入手教程(超简单)

前言 因为最近想学习AI&#xff0c;所以准备开始用python&#xff0c;所以为了照顾和我一样用win7且认为网上的教程难以操作的人&#xff0c;所以的算水写一篇博客。 正文 安装步骤&#xff1a; 打开python官网。&#xff08;会有一点慢&#xff0c;要耐心。&#xff09; …

回归预测 | Matlab实现CPO-CNN-LSTM-Attention冠豪猪优化卷积长短期记忆神经网络注意力机制多变量回归预测(SE注意力机制)

回归预测 | Matlab实现CPO-CNN-LSTM-Attention冠豪猪优化卷积长短期记忆神经网络注意力机制多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | Matlab实现CPO-CNN-LSTM-Attention冠豪猪优化卷积长短期记忆神经网络注意力机制多变量回归预测&#xff08;SE注…

C#,哥伦布数(Golomb Number)的算法与源代码

1 哥伦布数&#xff08;Golomb Number&#xff09; 哥伦布数&#xff08;Golomb Number&#xff09;是一个自然数的非减量序列&#xff0c;使得n在序列中正好出现G&#xff08;n&#xff09;次。前几个15的G&#xff08;n&#xff09;值为&#xff1a;1 2 2 3 3 4 4 4 5 5 5 6…

线阵相机参数介绍之帧加行触发

要点&#xff1a; 了解行触发与帧触发的区别 了解线阵相机帧行触发的参数设置 目标&#xff1a; 能够独立进行帧行触发的配置 1.帧、行触发的区别 帧触发控制的是一张图像开始拍摄的位置 行触发控制的是图像中每一行开始拍摄的位置。

极速上手:使用Jmeter轻松实现N种参数化

参数化的方式&#xff1a; 一、使用用户自定义变量 一种方式&#xff1a;直接在测试计划中添加用户自定义变量 另外一种方式&#xff1a;配置元件——用户自定义变量 示例&#xff1a;用户自定义变量&#xff0c;登录手机号码 在接口请求的时候&#xff0c;进行引用 请求之后&…

【iOS ARKit】3D 人体姿态估计

与基于屏幕空间的 2D人体姿态估计不同&#xff0c;3D人体姿态估计是尝试还原人体在三维世界中的形状与姿态&#xff0c;包括深度信息。绝大多数的现有3D人体姿态估计方法依赖2D人体姿态估计&#xff0c;通过获取 2D人体姿态后再构建神经网络算法&#xff0c;实现从 2D 到 3D人体…

极速搭建幻兽帕鲁私服,叫上好友春节假期一起联机畅玩帕鲁

文章目录 前言幻兽帕鲁私服详细部署教程查看服务器开始游戏自定义游戏参数配置 前言 行业资讯 《幻兽帕鲁》的火爆对开发商 Pocketpair 来说&#xff0c;代价是巨大的。该游戏的成功让首席执行官沟部拓郎最近在推特上表示&#xff0c;他可能因服务器运营费用而面临破产。据他透…

Matplotlib绘制炫酷散点图:从二维到三维,再到散点图矩阵的完整指南与实战【第58篇—python:Matplotlib绘制炫酷散点图】

文章目录 Matplotlib绘制炫酷散点图&#xff1a;二维、三维和散点图矩阵的参数说明与实战引言二维散点图三维散点图散点图矩阵二维散点图进阶&#xff1a;辅助线、注释和子图三维散点图进阶&#xff1a;动画效果和交互性散点图矩阵进阶&#xff1a;调整样式和添加密度图总结与展…

Backtrader 文档学习-Indicators- TA-Lib

Backtrader 文档学习-Indicators- TA-Lib 1.概述 即使BT提供的内置指标数量已经很多&#xff0c;开发指标主要是定义输入、输出并以自然方式编写公式&#xff0c;还是希望使用TA-LIB。原因: 指标X在指标库中&#xff0c;而不在BT中TA-LIB众所周知的&#xff0c;人们信任口碑…