浅克隆(ShallowClone)和深克隆(DeepClone)区别以及实现

什么是克隆

克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。

浅克隆和深克隆区别

  • 浅克隆: 被Clone的对象的所有变量都含有原来对象相同的值,而引用变量还是原来对用的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。
  • 深克隆: 被克隆对象的所有变量都含有原来的对象相同的值,引用变量也重新复制了一份【不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象
    在这里插入图片描述

浅克隆demo

public class Student {
	private Long id;
	private String name;
	private Integer sex;
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getSex() {
		return sex;
	}
	public void setSex(Integer sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", sex=" + sex + "]";
	}
}

public class Clazz implements Cloneable {

	private Long number;
	private String name;
	private Student stu;
	
	@Override
	protected Clazz clone() throws CloneNotSupportedException {
		Clazz cla = (Clazz)super.clone();
		return cla;
	}
	
	public Long getNumber() {
		return number;
	}
	public void setNumber(Long number) {
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Student getStu() {
		return stu;
	}
	public void setStu(Student stu) {
		this.stu = stu;
	}
	@Override
	public String toString() {
		return "Clazz [number=" + number + ", name=" + name + ", stu=" + stu + "]";
	}
}

public class CloneTest {
	
	public static void main(String[] args) throws CloneNotSupportedException {
		test();
	}
	
	private static void test() throws CloneNotSupportedException {
		Clazz cla = getClazz();
		 System.out.println("cla_1>:"+cla+"cla_1.hashCode>:"+cla.hashCode()+"-----cla_1_stu.hashCode>:"+cla.getStu().hashCode());
		 Clazz cla2 = cla.clone();
		 System.out.println("cla_2>:"+cla2+"cla_2.hashCode>:"+cla2.hashCode()+"-----cla_2_stu.hashCode>:"+cla2.getStu().hashCode());
		
		 cla2.setName("999体育班");
		 Student changeStu = cla2.getStu();
		 changeStu.setName("小王");
		 changeStu.setId(2L);
		 changeStu.setSex(1);
		 System.out.println("-----修改了Clone出来的Clazz.name以及Clazz.stu.name----------");
		 System.out.println("cla_1>:"+cla+"cla_1.hashCode>:"+cla.hashCode()+"-----cla_1_stu.hashCode>:"+cla.getStu().hashCode());
		 System.out.println("cla_2>:"+cla2+"cla_2.hashCode>:"+cla2.hashCode()+"-----cla_2_stu.hashCode>:"+cla2.getStu().hashCode());
		 
	}
	
	private static Student getStudent() {
		Student stu = new Student();
		stu.setId(1L);
		stu.setName("小李");
		stu.setSex(0);
		return stu;
	}
	
	private static Clazz getClazz() {
		Clazz cla = new Clazz();
		cla.setNumber(324L);
		cla.setName("文化班");
		cla.setStu(getStudent());
		return cla;
	}

}

  • 打印结果:
    在这里插入图片描述
    由此可见,浅克隆,被克隆对象中的引用还是一样的,hashCode值也是一样的

深克隆demo

public class Student implements Cloneable{
	
	private Long id;
	private String name;
	private Integer sex;
	
	@Override
	protected Student clone() throws CloneNotSupportedException {
		return (Student)super.clone();
	}
	
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getSex() {
		return sex;
	}
	public void setSex(Integer sex) {
		this.sex = sex;
	}
	
	
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", sex=" + sex + "]";
	}
}
public class Clazz implements Cloneable {

	
	private Long number;
	private String name;
	private Student stu;
	
	
	@Override
	protected Clazz clone() throws CloneNotSupportedException {
		Clazz cla = (Clazz)super.clone();
		cla.stu = stu.clone(); // 引用对象也需要Clone
		return cla;
	}
	
	public Long getNumber() {
		return number;
	}
	public void setNumber(Long number) {
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Student getStu() {
		return stu;
	}
	public void setStu(Student stu) {
		this.stu = stu;
	}

	@Override
	public String toString() {
		return "Clazz [number=" + number + ", name=" + name + ", stu=" + stu + "]";
	}
	
}
// 同样的CloneTest.java就不复制出来了

  • 打印结果
    在这里插入图片描述
    浅克隆,被克隆对象中的引用(hashCode值)不一样,cla和cla2中的stu是两个不同的对象,不同的内存地址

附:

cloneable接口的作用

cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。Object中clone方法:

这里有一个疑问,Object中的clone方法是一个空的方法,那么他是如何判断类是否实现了cloneable接口呢?

原因在于这个方法中有一个native关键字修饰。

native修饰的方法都是空的方法,但是这些方法都是有实现体的(这里也就间接说明了native关键字不能与abstract同时使用。因为abstract修饰的方法与java的接口中的方法类似,他显式的说明了修饰的方法,在当前是没有实现体的,abstract的方法的实现体都由子类重写),只不过native方法调用的实现体,都是非java代码编写的(例如:调用的是在jvm中编写的C的接口),每一个native方法在jvm中都有一个同名的实现体,native方法在逻辑上的判断都是由实现体实现的,另外这种native修饰的方法对返回类型,异常控制等都没有约束。

由此可见,这里判断是否实现cloneable接口,是在调用jvm中的实现体时进行判断的。

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 在 JavaScript 中,克隆一个对象通常可以通过递归实现。具体来说,需要遍历对象的每一个属性,如果某个属性是对象或数组,那么需要递归地进行克隆,否则直接将其赋值给新对象即可。 以下是一个简单的克隆实现: ```javascript function deepClone(obj) { if (obj === null || typeof obj !== "object") { // 如果不是对象或数组,则直接返回 return obj; } const clone = Array.isArray(obj) ? [] : {}; // 判断是数组还是对象 // 遍历每个属性并递归克隆 for (let key in obj) { clone[key] = deepClone(obj[key]); } return clone; } ``` 这个函数可以接受任何类型的对象作为参数,并返回一个克隆后的对象。需要注意的是,该函数有一些限制: - 该函数不支持循环引用,如果原对象中有循环引用,将会导致栈溢出错误。 - 该函数不会克隆对象的原型链,只会克隆自身的属性。 因此,在使用这个函数时需要注意它的限制。如果需要处理循环引用或者原型链,需要使用更为复杂的实现。 ### 回答2: 在JavaScript中实现对象的克隆,可以通过以下步骤实现: 1. 创建一个函数,命名为deepClone,该函数将接收一个参数obj,表示需要克隆的对象。 2. 首先判断obj的类型,如果obj是基本数据类型或者是null,则直接返回该值,因为基本数据类型是按值传递的,不存在引用关系。 3. 创建一个变量cloneObj,用于保存克隆后的对象。 4. 遍历obj的属性,使用for...in循环遍历obj的所有可枚举属性。 5. 在遍历的过程中,判断obj的属性值的类型,如果属性值是对象或者数组,则递归调用deepClone函数进行克隆,将返回的克隆值赋给cloneObj的对应属性。 6. 如果属性值是基本数据类型或者是函数,则直接赋值给cloneObj的对应属性。 7. 最后,返回cloneObj,即为克隆后的对象。 以下是一个实现克隆的代码示例: function deepClone(obj) { if (obj === null || typeof obj !== "object") { return obj; } let cloneObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { cloneObj[key] = deepClone(obj[key]); } } return cloneObj; } 使用方法如下: const obj = { name: "Alice", age: 20, hobbies: ["coding", "reading"], address: { city: "Beijing", country: "China" } }; const clonedObj = deepClone(obj); console.log(clonedObj); 上述代码能够将obj克隆得到一个独立的对象clonedObj,两者完全独立,修改其中一个对象不会影响另一个对象。 ### 回答3: 对象的克隆是指将一个对象完全复制一份,并且新对象与原对象没有任何引用关系。Javascript实现对象的克隆可以通过以下步骤: 1. 创建一个空的目标对象,用于存储克隆后的对象。 2. 遍历原始对象的属性,使用递归的方式克隆每个属性的值。 3. 对于原始对象的每个属性,判断其类型: - 若为基本数据类型(如字符串、数字、布尔值等),直接复制到目标对象。 - 若为引用类型(如对象、数组等),则需要再次进行克隆操作。 4. 对于引用类型的属性,根据其具体类型进行不同的处理: - 若为数组,创建一个新的空数组,并遍历原数组,递归地将每个元素克隆到新数组中。 - 若为对象,创建一个空对象,并遍历原对象的属性,递归地将每个属性值克隆到新对象中。 5. 将克隆后的属性值赋值给目标对象对应的属性。 6. 最后返回目标对象,完成克隆操作。 下面是一个简单的Javascript代码示例: function cloneObject(source) { let target = {}; for(let key in source) { if(typeof source[key] === 'object' && source[key] !== null) { if(source[key].constructor === Array) { // 克隆数组 target[key] = source[key].map(item => cloneObject(item)); } else { // 克隆对象 target[key] = cloneObject(source[key]); } } else { // 复制基本数据类型 target[key] = source[key]; } } return target; } 使用该函数进行对象的克隆: let obj1 = {a: 1, b: {c: 2}}; let obj2 = cloneObject(obj1); console.log(obj2); // 输出: {a: 1, b: {c: 2}} console.log(obj1 === obj2); // 输出: false

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值