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

​     当我们想复制一个对象时,最自然的操作就是直接赋值给另一个变量,这种做法只是,复制了对象的地址,两个变量指向了同一个对象,任意一个变量操作对象的属性,都会影响到另一个变量。 (如下)

Person p1 = new Person(17);
Person p2 = p1;   // 直接赋值
p2.age = 20;  // 使用 p2 给属性赋值

System.out.println(p1 = p2);   // true 
System.out.println(p1.age);   // 20

    这种对同一个对象的操作,当然算不上复制。(所以,引用拷贝并不算是对象拷贝)

    我们一般说的对象拷贝,就是指,浅拷贝 和 深拷贝。

先说浅拷贝

public class Object {
    protected native Object clone() throws CloneNoSupportedExpection;
}

    Object 提供了一个 clone() ,

    看名字就知道,它和对象拷贝有关,

    该方法的访问修饰符为 protected,

    如果子类不重写该方法,并将其声明为 public ,那外部就调用不了,对象的 clone(),

    子类在重写时直接调用,Object 的 clone()

public class Demo01 {

    public int age;
    
    public Demo01() {
    }

    public Demo01(int age) {
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    
    
    // 调用
    
        public static void main(String[] args) throws CloneNotSupportedException {
        Demo01 d1 = new Demo01(18);

        Demo01 clone = (Demo01)d1.clone();
        
        d1.age = 20;

    }
}

它是 native 方法,底层已经实现了拷贝对象的逻辑,

这里要注意,子类一定要实现 Cloneable 接口,

否则在调用 clone() 时,就会抛出异常,这是 java 的规定。

现在我们就可以调用 clone() 方法 来复制对象了。

Person p1 = new Person(18);
Person p2 = new Person();
p2.age = 20;

System.out.println(p1 = p2);   // false 
System.out.println(p1.age);   // 18

    此时,会发现,两个对象指向的是两个不同的对象,各自改变属性,也不会影响到另一个对象,

    看起来效果很好,但是有一个问题:如果拷贝的对象中,有属性是引用类型,那这种浅拷贝的方式

public class Person implements Cloneable {


    public int age;
    public int[] arr = new int[]{1,2};

    public Person() {
        
    }

    public Person(int age, int[] arr) {
        this.age = age;
        this.arr = arr;
    }


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

    只是会复制该属性的引用地址,即拷贝对象和原对象,都指向了同一个引用类型(对象)

    如果对这个属性,进行一些操作,则会影响到另一个对象的属性。

    若是想将对象中的引用类型属性也进行拷贝。

    那就需要用到 深拷贝了。

简单将代码修改一下

@Override
protected Object clone() throws CloneNotSupportedException {
    Person person = (Person) super.clone();
    person.arr = this.arr.clone();
    return person;
}

    克隆出对象之后,然后再对引用类型的属性进行复制。

    此时,对象中的属性也指向了不同的实例

引用拷贝、浅拷贝、深拷贝之间的区别!

区别
引用拷贝 只是复制对象的地址,并不会创建一个新对象。
浅拷贝 会创建一个新对象,并进行属性的复制。但是对引用类型的属性,只会复制其地址。
深拷贝 完全复制整个对象,包括引用类型的对象。

​     实际开发中,不建议使用,因为有抛出异常的风险,如果真想让对象提供拷贝功能,那就自己编写吧!

posted @   走马!  阅读(267)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示
主题色彩