引用拷贝、浅拷贝、深拷贝

1,333 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

引用拷贝、浅拷贝、深拷贝

我们复制一个对象到另一个对象,这种情况就叫做拷贝,而拷贝又分为引用拷贝、浅拷贝、深拷贝,它们具体是指什么呢,在日常的开发过程中,搞懂它是非常有必要的。

引用拷贝

引用拷贝感觉上像是地址引用,仅仅拷贝了地址而已,而所有的地址其实指向一个对象。引用地址存在栈中,实际的对象存在堆中。引用拷贝,就是拷贝引用地址。

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)

图是不是有些混乱,来看个具体的。

Image.png

怎么实现浅拷贝呢?

  1. 在需要拷贝的类上实现Cloneable接口并重写其clone()方法
  2. 使用的时候直接调用类的clone()方法
         implements Cloneable

         /**
         * 重写clone()方法
         *
         * @return
         */
        @Override
        public Object clone() {
            try {
                return super.clone();
            } catch (CloneNotSupportedException e) {
                return null;
            }
        }

深拷贝

深拷贝创建一个新的对象,是完全独立于原对象的,所以无论怎么修改属性,另一个对象中的属性也不会随着改变。

看图

Image [1].png

如何实现深拷贝呢。

序列化是大家公认的一种方式。

比如一种比较巧妙的方法,先将对象转JSON,然后再用JSON转成对象。