[Java基础]拷贝类型

拷贝类型#

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

引用拷贝
在Java中,对象的引用拷贝是指将一个对象的引用赋值给另一个变量。通过引用拷贝,两个变量将指向同一个对象,它们共享同一块内存空间。当修改其中一个变量指向的对象时,另一个变量也会受到影响。

下面是一个简单的示例代码,演示了对象引用拷贝的概念:

public class Test {
    public static void main(String[] args) {

        // 创建一个Person对象
        Person person1 = new Person("Alice", 25);

        // 将person1的引用拷贝给person2
        Person person2 = person1;

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);

        // 修改person1的属性
        person1.setName("Bob");
        person1.setAge(30);

        System.out.println("person1: " + person1);
        System.out.println("person2: " + person2);
		
        // True
        System.out.println(person1 == person2);

    }

}


class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    @Override
    public String toString() {
        return "Person[name=" + name + ", age=" + age + "]";
    }
}

在上述代码中,创建了一个Person对象person1,然后将其引用拷贝给person2。修改person1的属性后,打印person1和person2的值,可以发现它们指向同一个对象,因此修改person1的属性后,person2的属性也会相应改变。

输出结果如下:

person1: Person[name=Alice, age=25]
person2: Person[name=Alice, age=25]
person1: Person[name=Bob, age=30]
person2: Person[name=Bob, age=30]

true

可以看到,通过引用拷贝,person1和person2指向同一个Person对象,修改其中一个对象的属性会影响另一个对象。

浅拷贝
在Java中,浅拷贝(Shallow Copy)是指创建一个新对象,并将原始对象中的所有字段的值复制到新对象中。浅拷贝只是简单地复制对象的字段值,如果是基本数据类型,那就是简单复制值,如果是引用数据类型那就是复制引用地址值。

要实现浅拷贝,可以使用以下几种方式:

使用Object类的clone()方法:Object类中的clone()方法可以复制一个对象,但它只复制对象的字段值,不复制引用类型字段指向的对象。因此,如果对象中包含引用类型字段,那么新对象和原始对象会共享这些引用类型的字段。

使用拷贝构造函数:通过定义一个构造函数,参数为原始对象,将原始对象中的字段值复制到新对象中。

需要注意的是,浅拷贝只是复制对象的字段值,而不复制对象内部的引用类型字段的值。因此,如果需要实现深拷贝,就需要对引用类型字段进行递归拷贝,确保新对象和原始对象的引用类型字段指向不同的对象。

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Address(String address) {
        this.address = address;
    }
}

class Person implements Cloneable {
    private String name;
    private int age;

    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return this.name + "-" + this.age + "-" + this.address.getAddress();
    }

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

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {

        Address address1 = new Address("山东");
        Person person1 = new Person("Alice", 25, address1);
        Person person2 = (Person) person1.clone();

        System.out.println(person1);
        System.out.println(person2);

        person1.setAge(30);
        address1.setAddress("上海");

        System.out.println(person1);
        System.out.println(person2);
        
        //Alice-25-山东
        //Alice-25-山东
        //Alice-30-上海
        //Alice-25-上海

    }

}

深拷贝
在 Java 中,深拷贝(Deep Copy)是指创建一个新对象,将原始对象中的所有字段的值都复制到新对象中。深拷贝会递归复制对象的所有层级,包括对象的引用类型字段,确保新对象和原始对象完全独立相对地,浅拷贝(Shallow Copy)只是简单地复制对象的字段值,如果对象中包含引用类型的字段,那么新对象和原始对象会共享这些引用类型的字段。

为了实现深拷贝,可以使用以下几种方式:

实现 Cloneable接口和覆写 clone() 方法:通过实现 Cloneable 接口来指明对象可以进行拷贝操作,并覆写 clone() 方法来实现深拷贝的逻辑。

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        
        Person person1 = new Person("Alice", 25, new Address("山东"));
        Person person2 = (Person) person1.clone();

        System.out.println(person1);
        System.out.println(person2);

        person2.setName("david");
        person2.setAge(30);
        person2.getAddress().setAddress("上海");

        System.out.println(person1);
        System.out.println(person2);
        
        
        //Alice-25-山东
        //Alice-25-山东
        //Alice-25-山东
        //david-30-上海

    }

}

public class Address implements Cloneable{
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Address(String address) {
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Address clone = (Address) super.clone();
        clone.setAddress(this.address);
        return clone;
    }
}




class Person implements Cloneable {
    private String name;
    private int age;

    private Address address;

    public Person(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public Person() {

    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return this.name + "-" + this.age + "-" + this.address.getAddress();
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person res = (Person) super.clone();
        res.address = (Address) this.address.clone();
        return res;
    }
}


使用序列化和反序列化:通过将对象序列化为字流,再将字节流反序列化为新对象来实现深拷贝。

public class MyClass implements Serializable {
    private int value;
    private MyObject obj;

    // 构造函数和其他方法
    
    public MyClass deepCopy() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this); // 序列化当前对象
    
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (MyClass) ois.readObject(); // 反序列化生成新对象
    }

}

需要注意的是,为了现深拷贝,不仅仅需要拷贝对象本身,还需要拷贝对象内部的引用类型字段。因此,如果引用类型字段也需要支持深拷贝,那么该引用类型也需要实现 Cloneable 接口或者序列化接口,并在拷贝方法中进行递归拷。

浅拷贝和深拷贝的区别
在Java中,浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是两种不同的对象拷贝方式,它们的主要区别如下:

  • 复制的内容不同:
    • 浅拷贝只复制对象的字段值,不复制引用类型字段指向的对象。
    • 深拷贝会递归复制对象的所有层级,包括对象的引用类型字段。
  • 对象的独立性不同:
    • 浅拷贝复制后的对象与原始对象共享相同的引用类型字段,即它们指向相同的对象。
    • 深拷贝复制后的对象与原始对象完全独立,它们的引用类型字段指向不同的对象。
  • 对象修改的影响不同:
    • 浅拷贝中,如果修改新对象的引用类型字段的值,原始对象的相应字段也会被修改,因为它们指向同一个对象。
    • 深拷贝中,修改新对象的引用类型字段的值不会影响原始对象的相应字段,因为它们指向不同的对象。
  • 实现方式不同:
    • 浅拷贝可以通过Object类的clone()方法、拷贝构造函数等方式实现。
    • 深拷贝需要对对象的引用类型字段进行递归拷贝,可以通过实现Cloneable接口和覆盖clone()方法、使用序列化和反序列化等方式实现。

总结来说,浅拷贝只复制对象的字段值,不复制引用类型字段指向的对象,而深拷贝会递归复制所有层级的对象,确保新对象和原始对象完全独立。因此,深拷贝相比浅拷贝更加安全,但也需要更多的资源和性能开销。选择使用哪种拷贝方式,需要根据具体的场景和需求来决定。

作者:Esofar

出处:https://www.cnblogs.com/DCFV/p/18292608

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Duancf  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示