克隆之所以有深浅之分,是因为在Java、python中,数据类型有基本数据类型、引用数据类型
java中的基本数据类型存储在栈中,引用数据类型存储在堆里
标记接口里并没有成员,其作用只是为这个类打上一个标记。就像公务员招考,对于某个工作岗位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中的引用类新型也被修改了
}
}
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();
}
}
基本数据类型、引用数据类型的原理是一样的,但实现方法当然是不一样的了
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']] 未发生改变