java 中 Object 的操作都是引用。原始数据类型操作都是值拷贝。
这里的操作就包括 赋值 和 函数参数传递
这里说明下 java 中的概念:
java中所有的类都隐形继承了 Obejct 类
java中数组也是 Object,官方原话:
An object is a class instance or an array.
赋值
Demo:
1 | class C{ |
Debug显示:
b = {B@785}
b_value = 1
b_c_class = {C@790}
bb = {B@785}
b_value = 1
b_c_class = {C@790}
i = {Integer[1]@786}
0 = {Integer@788} 100
ii = {Integer[1]@786}
0 = {Integer@788} 100
i2 = {Integer@787}
value = 3
ii2 = {Integer@789}
value = 101
可以发现,只有 Integer 的赋值是重新开辟了一块内存来存放原数据。
其他的 Object 类型操作都是 引用赋值。即直接将内存地址的指针指向原地址,复用原地址的数据,而不是重新开辟内存。这样导致的结果就是:
a变量直接赋值给b变量,修改 b变量,a变量也会受到影响,因为他们的内存地址指针指向的是同一块内存地址。
那如何让 Object 赋值的时候重新开辟内存呢?Object 中提供了一个 clone() 方法
数组值拷贝
Demo:
1 | Integer[] i = {1}; |
Debug显示:
i = {Integer[1]@782}
0 = {Integer@785} 1
ii = {Integer[1]@783}
0 = {Integer@784} 100
数组值拷贝,使用 clone() 方法即可
类拷贝
如果要拷贝的对象是我们自定义的类的话,是没法直接 clone的。需要 实现 Cloneable 接口,重写 clone() 方法,并且 catch 住 CloneNotSupportedException
浅拷贝
Demo:
1 | class C{ |
Debug 显示:
b = {B@783}
b_value = 1
b_c_class = {C@785}
c_value = 300
bb = {B@784}
b_value = 200
b_c_class = {C@785}
c_value = 300
对象浅拷贝即:拷贝时目标变量确实重新拷贝了原对象的值,但是原对象中保存的其他对象依然只是单纯地把地址拷贝到目标变量,并不是重新拷贝一份。
即上面Demo中,b_c_class 保存的是对象C 的值。 bb 中保存的 b_c_class 指向的地址 和 b 中b_c_class 指向的地址是同一块内存,所以修改 bb对象 中的 b_c_class,b对象也会受到牵连
深拷贝
为了让 bb对象 中的 b_c_class 重新拷贝一份 C对象。需要修改下 clone() 方法。
实现 C类 的clone()方法,然后在 B类 处手动 clone b_c_class
Demo:
line 27 处将 C对象 重新clone一份
1 | class C implements Cloneable{ |
Debug显示:
b = {B@784}
b_value = 1
b_c_class = {C@787}
c_value = 100
bb = {B@785}
b_value = 200
b_c_class = {C@786}
c_value = 300
现在确实可以将 对象中的对象 进行拷贝了。但是如果对象的层数很多的话,就显得很麻烦了。
还可以通过序列化的方式来进行对象拷贝,这种方式更方便。
序列化的时候需要注意:被序列化的类需要实现 Serializable 接口
Demo:
1 | import java.io.*; |
Debug显示:
b = {B@945}
b_value = 1
b_c_class = {C@950}
c_value = 100
c_array = {Integer[1]@951}
0 = {Integer@952} 20
bb = {B@946}
b_value = 200
b_c_class = {C@947}
c_value = 300
c_array = {Integer[1]@948}
0 = {Integer@949} 30
Reference: