Java/Python克隆(深浅克隆)原理及实现

Java中的克隆


1.浅复制与深复制概念

(1)浅复制(浅克隆)被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然只指向原来的对象,换言之,浅复制仅仅复制锁考虑的对象,而不复制它所引用的对象。(2)深复制(深克隆)被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制过的新对象,而不再试原有的那些被引用的对象,换言之,深复制把要复制的对象所引用的对象都复制了一遍。

实现ICloneable接口的方式取决于我们的类型的数据成员。如果类型仅包含值类型(int,byte等类型)和string类型的数据成员,我们只要在Clone方法中初始化一个新的对象,将其的数据成员设置为当前对象的各个成员的值即可。事实上,object类的MemberwiseClone方法会自动完成该过程。

如果自定义类型包含引用类型的数据成员,必须考虑Clone方法是实现浅拷贝(shallow copy)还是深拷贝(deep copy)。浅拷贝是指副本对象中的引用类型的数据成员与源对象的数据成员指向相同的对象。而如果是深拷贝,则必须创建整个对象的结构,副本对象中的引用类型的数据成员与源对象的数据成员指向不同的对象。

浅拷贝是容易实现的,就是使用前面提到的MemberwiseClone方法。开发人员往往希望使用的类型能够实现深拷贝,但会发现这样的类型并不多。这种情况在System.Collections命名空间中尤其常见,这里面的类在其Clone方法中实现的都是浅拷贝

 

2. java的clone()方法


(1)clone方法将对象复制了一份并返回给调用之,一般而言,clone()方法满足:
     对任何的对象C=X,都有x.clone()!=x//克隆对象与源对象不是同一个对象
     对任何的对象X,都有x.clone().getClass()==x.getClass()//克隆对象与源对象类型一样
     如果对象X的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

(2)java对象中的克隆
    为了获取对象的一份拷贝,我们可以利用Object类得clone()方法。
    在派生类中覆盖基类的clone(),并声明为public。
    在派生类的clone()方法中,调用super.clone().
    在派生类中实现Cloneable接口

 

【参考】https://blog.csdn.net/hello_kevinkuang/article/details/7654539

Python中的克隆


浅拷贝:不拷贝子对象(针对子对象中的item),当子对象进行更改的时候,原始对象也会改变。常见操作:列表的切片[:]操作、list()操作,字典的copy()函数、copy模块的copy()函数(两个一模一样的双胞胎)

深拷贝:会拷贝子对象,当对原始对象子对象进行更改的时候,原始对象不会改变。

实现:

import copy
list_0 = ["A", "B", ["C", "D"], "E"]
list_1 = copy.copy(list_0)
list_2 = list_0.copy()
list_3 = list_0[:]
list_4 = list(list_0)

# --- 深拷贝的拷贝方式 ---
list_d = copy.deepcopy(list_0)


# --- 深浅拷贝的区别 ---
# 1. 对第一层数据进行赋值
list_0[0] = "X0"
list_1[0] = "X1"
list_2[0] = "X2"
list_3[0] = "X3"
list_4[0] = "X4"
list_d[0] = "Xd"

# 打印结果: 理所当然,所有列表都发生了变化
# list_0: ['X0', 'B', ['C', 'D'], E]
# list_1: ['X1', 'B', ['C', 'D'], E]
# list_2: ['X2', 'B', ['C', 'D'], E]
# list_3: ['X3', 'B', ['C', 'D'], E]
# list_4: ['X4', 'B', ['C', 'D'], E]
# list_d: ['Xd', 'B', ['C', 'D'], E]

# 2. 对第二层的list引用进行赋值
list_0[2][0] = "Y0"
list_1[2][0] = "Y1"
list_2[2][0] = "Y2"
list_3[2][0] = "Y3"
list_4[2][0] = "Y4"
list_d[2][0] = "Yd"

# 打印结果: 0-1都被改成了同一个值,这说明浅拷贝只拷贝了第二层list的引用;而深拷贝则拷贝了数据结构
# list_0: ['X0', 'B', ['Y4', 'D'], E]
# list_1: ['X1', 'B', ['Y4', 'D'], E]
# list_2: ['X2', 'B', ['Y4', 'D'], E]
# list_3: ['X3', 'B', ['Y4', 'D'], E]
# list_4: ['X4', 'B', ['Y4', 'D'], E]
# list_d: ['Xd', 'B', ['Yd', 'D'], E]

# 3. 对第三层的Ls对象引用进行赋值
list_0[3]= "Z0"
list_1[3]= "Z1"
list_2[3]= "Z2"
list_3[3]= "Z3"
list_4[3]= "Z4"
list_d[3]= "Zd"

# 执行结果: 继续验证了上方论点
# list_0: ['X0', 'B', ['Y4', 'D'], Z4]
# list_1: ['X1', 'B', ['Y4', 'D'], Z4]
# list_2: ['X2', 'B', ['Y4', 'D'], Z4]
# list_3: ['X3', 'B', ['Y4', 'D'], Z4]
# list_4: ['X4', 'B', ['Y4', 'D'], Z4]
# list_d: ['Xd', 'B', ['Yd', 'D'], Zd]
print(list_0)
print(list_1)
print(list_2)
print(list_3)
print(list_4)
print(list_d)

【小结】

思路一:利用切片操作和list方法拷贝等就叫浅拷贝,只是拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。

思路二:利用copy中的deepcopy方法进行拷贝就叫做深拷贝,外围和内部元素都进行了拷贝对象本身,而不是引用。    

但是对于数字,字符串和元组类型对象,没有被拷贝的说法,即便是用深拷贝,查看id的话也是一样的,如果对其重新赋值,也只是新创建一个对象,替换掉旧的而已。

你可能感兴趣的:(Python)