小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
引用拷贝、浅拷贝、深拷贝
我们复制一个对象到另一个对象,这种情况就叫做拷贝,而拷贝又分为引用拷贝、浅拷贝、深拷贝,它们具体是指什么呢,在日常的开发过程中,搞懂它是非常有必要的。
引用拷贝
引用拷贝感觉上像是地址引用,仅仅拷贝了地址而已,而所有的地址其实指向一个对象。引用地址存在栈中,实际的对象存在堆中。引用拷贝,就是拷贝引用地址。
graph TD
A(地址) --> 堆[堆内存]
B(拷贝地址1) --> 堆[堆内存]
C(拷贝地址2) --> 堆[堆内存]
无论哪个地址都指向着同一个地方
Person person = new Person();
Person person1 = person;
这样无论是改变person还是person1的属性,都会跟着改变。
浅拷贝
浅拷贝的含义有些复杂,总结一下什么是浅拷贝。
浅拷贝会创建一个新的对象,新的对象和原本对象不相等,内存区域也不同,但是新对象的属性和老对象的相同。
- 如果属性是基本类型(int,double,long,boolean等),拷贝的就是基本类型的值;
- 如果属性是引用类型,拷贝的就是内存地址(即复制引用但不复制引用的对象)
注:String类型通过常量赋值时相当于基本数据类型,由于String为不可变对象,是无法修改原String的状态的,其会生成一个新的String对象
这一点怎么理解呢,看图吧
graph TD
A(地址) --> X[堆内存对象1]
B(拷贝地址1) --> Y[堆内存对象2]
C(拷贝地址2) --> Z[堆内存对象3]
X --> D(子属性1)
Y --> D(子属性1)
Z --> D(子属性1)
X --> E(子属性2)
Y --> E(子属性2)
Z --> E(子属性2)
图是不是有些混乱,来看个具体的。
怎么实现浅拷贝呢?
- 在需要拷贝的类上实现Cloneable接口并重写其clone()方法
- 使用的时候直接调用类的clone()方法
implements Cloneable
/**
* 重写clone()方法
*
* @return
*/
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
深拷贝
深拷贝创建一个新的对象,是完全独立于原对象的,所以无论怎么修改属性,另一个对象中的属性也不会随着改变。
看图
如何实现深拷贝呢。
序列化是大家公认的一种方式。
比如一种比较巧妙的方法,先将对象转JSON,然后再用JSON转成对象。