深浅克隆

克隆之所以有深浅之分,是因为在Java、python中,数据类型有基本数据类型引用数据类型

先说一下Java中的

java中的基本数据类型存储在中,引用数据类型存储在

  • Java中的克隆需要 implement Cloneable这个标记接口
  • 并实现clone接口。(因为clone接口是 protected 的,Object包外、非Object子类无法使用。java访问控制

标记接口里并没有成员,其作用只是为这个类打上一个标记。就像公务员招考,对于某个工作岗位A,你行我也行,但是这个招考要求必须是“ 计算机科学与技术软件工程方向 ”,而你的学位证不是这个,那它就不让你参加考试。

浅克隆,只要求被克隆的类implement Cloneable,并重写clone方法

目录结构:
C继承A,T是main类
在这里插入图片描述
A:

public class A{
	public String sa;
	public A() {
		
	}
	public A(String s) {
		this.sa = s;
	}
}

C:

// Class C 中既有“基本数据类型”,也有“引用数据类型”
public class C implements Cloneable {
	// 基本数据类型
	public String name;
	// 引用数据类型
	public A a;

	public C(String name, A a) {
		this.name = name;
		this.a = a;
	}

	@Override
	protected C clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		C c = (C)super.clone();
		return c;
	}

}

T:

// 浅拷贝,引用数据类型未被clone
public class T {
	public static void main(String[] args) throws CloneNotSupportedException {
		C c1 = new C("this is C", a1);
		C c2 = (C)c1.clone();
		System.out.println(c2.a.sa); // this is a1
		c1.a.sa = "this is c1's A";
		System.out.println(c2.a.sa); // this is c1's A,c1中引用类型被修改后,c2中的引用类新型也被修改了
	}
}

深克隆,被克隆的类、以及该类引用的类都要implement Cloneable,并都重写 clone方法

A:

public class A implements Cloneable{
	public String sa;
	public A() {
		
	}
	public A(String s) {
		this.sa = s;
	}
	
	@Override
	public A clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return (A)super.clone();
	}

}

C:

// Class C 中既有“基本数据类型”,也有“引用数据类型”
public class C implements Cloneable {
	// 基本数据类型
	public String name;
	// 引用数据类型
	public A a;

	public C(String name, A a) {
		this.name = name;
		this.a = a;
	}

	@Override
	protected C clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		C c = (C)super.clone();
		c.a = a.clone();
		return c;
	}

}

T:

// 深拷贝,引用数据类型被clone
public class T {
	public static void main(String[] args) throws CloneNotSupportedException {
		C c1 = new C("this is C", a1);
		C c2 = (C)c1.clone();
		System.out.println(c2.a.sa); // this is a1
		c1.a.sa = "this is c1's A";
		System.out.println(c2.a.sa); // this is a1,深克隆后,c1修改自己的引用类,c2未发生改变
	}
}

通过序列化来实现深克隆

A:

import java.io.Serializable;

// Class A 中只有“基本数据类型”,所以在浅克隆时不会出现问题
public class A implements Serializable{
	public String sa;
	public A() {
		
	}
	public A(String s) {
		this.sa = s;
	}
}

C:

import java.io.Serializable;

// Class C 中既有“基本数据类型”,也有“引用数据类型”
public class C implements Serializable {
	// 基本数据类型
	public String name;
	// 引用数据类型
	public A a;

	public C(String name, A a) {
		this.name = name;
		this.a = a;
	}

}

T:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class T {
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		A a1 = new A("this is A");
		C c1 = new C("this is C", a1);
		C c2 = (C) deepClone(c1);
		System.out.println(c2.a.sa);
		c1.a.sa = "this is c1's A";
		System.out.println(c2.a.sa);
	}

	public static Object deepClone(Object obj) throws IOException, ClassNotFoundException {
		// 将obj写出去(写到内存里)
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		ObjectOutputStream oout = new ObjectOutputStream(bout);
		oout.writeObject(obj);
		// 再将内存里的读回来
		ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
		ObjectInputStream oin = new ObjectInputStream(bin);
		return oin.readObject();
	}

}

python中的

基本数据类型引用数据类型的原理是一样的,但实现方法当然是不一样的了

import copy

# 浅克隆1,只有基本数据类型
s1 = [i for i in range(3, 8)]
s2 = s1.copy()
print(id(s1) == id(s2)) # False
s1[0] = 484
print(s2) # [3, 4, 5, 6, 7] 未发生改变

s1.append(['hello', " ", "world"])
# 浅克隆2,包含引用数据类型
s3 = copy.copy(s1)
print(id(s1) == id(s3)) # False
s1[5][0] = 'hi'
print(s3) # [484, 4, 5, 6, 7, ['hi', ' ', 'world']] 发生改变

# 深克隆
s4 = copy.deepcopy(s1)
print(id(s1) == id(s4))
s1[5][0] = 'hello'
print(s4) # [484, 4, 5, 6, 7, ['hi', ' ', 'world']] 未发生改变
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值