引用拷贝,浅拷贝,深拷贝

参考资料

水平有限,欢迎交流!
kimi
【【每天一个技术点】引用拷贝、浅拷贝、深拷贝】
一文搞懂Java引用拷贝、浅拷贝、深拷贝 - bigsai - 博客园 (cnblogs.com)
【黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难】

1. 引用拷贝 (起绰号)

引用拷贝并不是真正意义上的拷贝,而是创建了一个新的指针指向已存在的数据。在这种拷贝方式下,原始数据和拷贝数据在内存中占用相同的位置。

特点:

  • 不创建新的对象,只是创建了一个新的引用(指针)指向已存在的对象。
  • 修改其中一个对象会影响另一个对象,因为他们指向同一个内存地址。

2. 浅拷贝(只拷贝基本数据类型,引用类型未在堆区开辟内存)

浅拷贝会创建一个新的对象,其字段值与原始对象相同。但是,如果原始对象的字段是引用类型,则拷贝的是引用,而不是实际的对象。

特点:

  • 创建一个新的对象,并将原始对象的值复制到新对象中。
  • 如果字段是基本类型,拷贝的是值。
  • 如果字段是引用类型,拷贝的是引用,而不是引用的对象。

3. 深拷贝(完全不同的对象,但值相同,在堆区开辟内存)

深拷贝会创建一个新的对象,并且递归地复制所有字段和它们的值。如果字段是对象,那么会为这个对象也创建一个拷贝。

特点:

  • 创建一个新的对象,并且递归地复制所有字段和它们的值。
  • 无论字段是基本类型还是引用类型,都会创建一个新的副本。

4.引用拷贝和浅拷贝在操纵引用类型变量(与原型引用变量的耦合关系)可能引发的问题

由于引用拷贝和浅拷贝在拷贝引用类型变量时仅仅是拷贝了其引用,而未在堆区申请内存,因此与原型变量存在耦合关系,改变一方,二者一起变化

  1. 修改影响: 如果通过一个引用修改了对象的状态,那么通过另一个引用观察到的对象状态也会发生改变,因为它们指向同一个对象。
  2. 并非独立: 程序员可能误以为两个引用是独立的,从而在代码中引入错误。
  3. 内存泄漏: 如果不小心,可能会导致内存泄漏,因为两个引用都指向同一个对象,导致对象无法被垃圾回收。
  4. 共享内部对象: 对于引用类型的字段,原始对象和浅拷贝对象仍然共享相同的内部对象,修改其中一个对象的引用类型字段会影响到另一个。

5. 案例

定义 Address 类

public class Address {  
    private String street;  
  
    public Address(String street) {  
        this.street = street;  
    }  
  
    public String getStreet() {  
        return street;  
    }  
  
    public void setStreet(String street) {  
        this.street = street;  
    }  
}

定义 Person 类

public class Person implements Cloneable{  
    private String name;  
    private Address address;  
  
    public Person(String name, Address address) {  
        this.name = name;  
        this.address = address;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Address getAddress() {  
        return address;  
    }  
  
    public void setAddress(Address address) {  
        this.address = address;  
    }  
    @Override  
    public Object clone() {  
        //浅拷贝  
        try {  
            return super.clone();  
        } catch (CloneNotSupportedException e) {  
            throw new AssertionError();  
        }  
    }  
    public Object deepClone() {  
        //深拷贝  
        try {  
            Person clonedPerson = (Person) super.clone();  
            clonedPerson.setAddress(new Address(this.getAddress().getStreet()));  
            return clonedPerson;  
        } catch (CloneNotSupportedException e) {  
            throw new AssertionError();  
        }  
    }  
}

定义主类

public class Main {  
    static Person original = new Person("Alice", new Address("123 Main St"));  
    public static void referenceCopy(){  
        // 引用拷贝  
        System.out.println("引用拷贝");  
        Person referenceCopy = original;  
        System.out.println(original==referenceCopy);  
        System.out.println(original.getAddress()==referenceCopy.getAddress());  
    }  
    public static void shallowCopy(){  
        // 浅拷贝  
        System.out.println("浅拷贝");  
        Person shallowCopy = null;  
        shallowCopy = (Person) original.clone();  
        System.out.println(original==shallowCopy);  
        System.out.println(original.getAddress()==shallowCopy.getAddress());  
    }  
    public static void deepCopy(){  
        // 深拷贝  
        System.out.println("深拷贝");  
        Person deepCopy = null;  
        deepCopy = (Person) original.deepClone();  
        System.out.println(original==deepCopy);  
        System.out.println(original.getAddress()==deepCopy.getAddress());  
    }  
    public static void main(String[] args) {  
        referenceCopy();  
        shallowCopy();  
        deepCopy();  
    }  
}

结果分析

运行结果

引用拷贝

original与referenceCopy: true

这意味着 referenceCopy 实际上是指向 original 的同一个对象。也就是说,referenceCopyoriginal 是同一个 Person 对象的不同引用,因此它们的地址是相同的。

original.getAddress()与referenceCopy.getAddress(): true

这表明 referenceCopyoriginal 共享同一个 Address 对象。因此,对其中一个对象的 Address 属性所做的任何更改都会反映到另一个对象上。

浅拷贝

original与shallowCopy: false

这意味着 shallowCopyoriginal 是两个不同的对象,即它们在内存中的地址不同。

original.getAddress()与shallowCopy.getAddress(): true

这表明虽然 shallowCopyoriginal 是不同的 Person 对象,但它们的 Address 属性引用的是同一个 Address 对象。因此,如果修改了 shallowCopyAddress 属性,那么 originalAddress 属性也会受到影响。

深拷贝

original与deepCopy: false

这表明 deepCopyoriginal 是两个不同的 Person 对象。

original.getAddress()与deepCopy.getAddress(): false

这表明 deepCopyoriginal 不仅是不同的 Person 对象,而且它们的 Address 属性也分别指向不同的 Address 对象。因此,对 deepCopyAddress 属性所做的任何更改都不会影响到 originalAddress 属性。

总结

  • 引用拷贝 创建了指向同一对象的新引用,所以任何对这个对象的更改都会影响到所有引用该对象的变量。
  • 浅拷贝 创建了一个新的顶层对象,但是其中的引用属性仍然指向原有的对象,所以对引用属性的更改会影响所有共享该引用的对象。
  • 深拷贝 创建了一个完全独立的新对象,包括所有嵌套的对象,因此对新对象的任何更改都不会影响到原对象。
posted @ 2024-09-28 21:12  yuanyulinyi  阅读(22)  评论(0编辑  收藏  举报