首页 > 其他分享 >深克隆和浅克隆的区别

深克隆和浅克隆的区别

时间:2023-08-22 11:24:53浏览次数:33  
标签:user2 克隆 user1 clone 区别 User Address

目录

赋值操作

@Getter
@Setter
public class User {
	private String name;
	private Address address;
}
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Address {
	private String city;
}

新对象通过复制原始对象得到

public class TestClone {

	public static void main(String[] args) {
		Address address = new Address();
		address.setCity("BJ");

		User user1 = new User();
		user1.setName("zhangsan");
		user1.setAddress(address);

		User user2 = user1; //赋值

		System.out.println("user1: " + user1.getName() + "," + user1.getAddress().getCity());
		System.out.println("user2: " + user2.getName() + "," + user2.getAddress().getCity());
		System.out.println("user是否相等:" + (user1 == user2)); //是同一个地址
		System.out.println("=====修改原始对象=====");

		user1.setName("lisi");
		user1.getAddress().setCity("SH");
		System.out.println("user1: " + user1.getName() + "," + user1.getAddress().getCity());
		System.out.println("user2: " + user2.getName() + "," + user2.getAddress().getCity());

	}
}

输出结果:
user1和user2就是同一个对象
新对象user2中的基本类型和引用类型的属性都会随user1中的变化而变化

user1: zhangsan,BJ
user2: zhangsan,BJ
user是否相等:true
=====修改原始对象=====
user1: lisi,SH
user2: lisi,SH

浅克隆

基本类型的属性复制值, 引用类型的属性复制地址

克隆: 实现 Cloneable 接口, 重写Object类中的 clone() 方法

类User实现clone()方法

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User implements Cloneable {
	private String name;
	private Address address;

	@Override
	public User clone() {
		User clone = null;
		try {
			clone = (User)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
}

新对象通过克隆原始对象得到

public class TestClone {

	public static void main(String[] args) {
		Address address = new Address();
		address.setCity("BJ");

		User user1 = new User();
		user1.setName("zhangsan");
		user1.setAddress(address);

		User user2 = user1.clone(); //克隆对象

		System.out.println("user1: " + user1.getName() + "," + user1.getAddress().getCity());
		System.out.println("user2: " + user2.getName() + "," + user2.getAddress().getCity());
		System.out.println("user是否相等:" + (user1 == user2));
		System.out.println("=====修改原始对象=====");

		user1.setName("lisi");
		user1.getAddress().setCity("SH");
		System.out.println("user1: " + user1.getName() + "," + user1.getAddress().getCity());
		System.out.println("user2: " + user2.getName() + "," + user2.getAddress().getCity());

	}

测试结果:
对象地址不一样, user1和user2已经不是同一个对象了
新对象中的基本类型的属性name不受user1的影响
引用类型属性会随着user1中的变化而变化, 因为二者的引用类型属性指向的还是同一个地址

user1: zhangsan,BJ
user2: zhangsan,BJ
user是否相等:false
=====修改原始对象=====
user1: lisi,SH
user2: zhangsan,SH

深克隆

基本类型属性和引用类型属性都和原始对象中的完全独立

引用类型属性的类Address也实现 clone() 方法

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Address implements Cloneable {
	private String city;

	@Override
	public Address clone() {
		Address address = null;
		try {
			address = (Address) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return address;
	}

}

User中的clone()方法中调用引用类型属性的克隆

@Getter
@Setter
public class User implements Cloneable {
	private String name;
	private Address address;

	@Override
	public User clone() {
		User clone = null;
		try {
			clone = (User)super.clone();
			//引用类型属性的克隆
			Address newAddress = address.clone();
			clone.setAddress(newAddress);
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return clone;
	}
}

测试结果:
新旧对象的地址不一样
user2的基本类型属性name 和 引用类型属性address 都不受原始对象的影响

user1: zhangsan,BJ
user2: zhangsan,BJ
user是否相等:false
=====修改原始对象=====
user1: lisi,SH
user2: zhangsan,BJ

常见的深克隆方式

1. 所有引用属性都实现克隆,整个对象就变成了深克隆。

上面的深克隆示例就是这种

2. 使用 JDK 自带的字节流序列化和反序列化对象实现深克隆。

//类必须实现Serializable接口
public class Address implements Serializable {/*...*/}
public class User implements Serializable {/*...*/}
//深克隆 java.io.*
User user2 = null;
try {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(user1);

    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bais);
    user2 = (User) ois.readObject();

} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

3. 使用第三方工具实现深克隆

比如 Apache Commons Lang。

4. 使用 JSON 工具

如 GSON、FastJSON、Jackson 序列化和反序列化对象实现深克隆。

    //fastjson
   	String str = JSONObject.toJSONString(user1);
	User user2 = JSONObject.parseObject(str, User.class);

参考

浅克隆和深克隆有什么区别?
https://www.cnblogs.com/javacn123/p/17407411.html

什么是深克隆,浅克隆?(案例详解)
https://www.cnblogs.com/blessing2022/p/16622041.html

浅克隆和深克隆
https://blog.csdn.net/ChineseSoftware/article/details/122942803

标签:user2,克隆,user1,clone,区别,User,Address
From: https://www.cnblogs.com/qode/p/17648058.html

相关文章

  • final、finally、finalize 有什么区别?
    final、finally和finalize是在Java中用于不同目的的关键字,它们的作用和使用方式有所不同:final:final是一个关键字,可以用于类、方法和变量。当用于类时,表示这个类不能再被继承(即不能有子类)。当用于方法时,表示这个方法不能被子类重写。当用于变量时,表示这个变量是一个常量,一旦赋......
  • 引言和摘要的区别
    引言和摘要是学术论文中两个不同的部分,它们在内容和目的上有明显的区别:引言(Introduction):目的:引言的主要目的是为读者提供论文研究的背景和上下文,引导读者进入论文的主题。它介绍了研究问题、研究背景、研究意义和研究目标,为后续论文内容提供了理论基础和论证的必要性。内......
  • Future和CompletableFuture区别
    Future:获取异步返回的结果需要使用轮询的方式,消耗cupExecutorServiceexecutorService=Executors.newFixedThreadPool(10);Future<String>future=executorService.submit(()->{try{Thread.sleep(2000);}......
  • import 和 require的区别
    import和require是两种用于加载模块的方式,主要区别如下:语法:import是ES6中的模块加载语法,require是Node.js中的模块加载语法。引用方式:import是静态引用,需要在模块的顶部引用,而且不能在代码中动态引用。require则可以在代码的任何地方引用,并且可以根据条件动态引用。导入的内容......
  • react class与hooks区别
    在React中,有两种主要的方式来管理组件的状态和生命周期:Class组件和Hooks。Class组件:Class组件是React最早引入的方式,它是基于ES6class的语法来创建的。Class组件包含了生命周期方法,可以用来处理组件的状态、副作用等。以下是一些Class组件的特点和生命周期方法:特点:使......
  • Nacos与Eureka的区别
    Nacos的服务实例分为两种l类型:临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。 Nacos与eureka的共同点 都支持服务注册和服务拉取都支持服务提供者心跳方式做健康检测 N......
  • 珠海先达盈致浅析MOM系统与MES系统的区别
    一、MOM系统与MES系统的区别MOM系统和MES系统是在制造业中较为重要的两类软件管理系统,它们在功能与应用上面有某些差别。MOM系统是一个综合性的的制造运营管理系统,它涵盖从生产计划到加工生产的整个生产制造过程。MOM系统主要关注运营管理,它可以在线监控和控制整个加工生产过程,包......
  • 营销干货 | CPM和oCPM有啥区别?
    我们之前用了三个章节的篇幅,讲明白了广告投放的正确方法、渠道选择,以及什么是全域营销。从本章开始,我们的内容将侧重于一些在广告投放领域需要重点学习、关注的专业术语、方法论,并解答一些来自读者的留言和常见的问题,希望可以助你在从事广告投放、市场营销等相关工作时,事半功倍,业......
  • 云主机与云服务器:两者的区别
    本文分享自天翼云开发者社区《云主机与云服务器:两者的区别》,作者:张****华云主机:云主机是一种通过虚拟化技术在云计算环境中提供的计算资源。它基于物理服务器上的虚拟机实例,可以进行灵活的配置和管理。云主机提供高可用性、弹性扩展和灵活的资源分配,使用户能够根据需求快速调整......
  • 微信小程序中的路由及其区别
    wx.navigateTo():保留当前页面,跳转到应用内的某个页面。但是不能跳到tabbar页面wx.redirectTo():关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到tabbar页面wx.switchTab():跳转到tabBar页面,并关闭其他所有非tabBar页面wx.navigateBack()关闭当前页面,返回上......