java 中的深拷贝与浅拷贝

java 中的深拷贝与浅拷贝

1 什么是浅拷贝和深拷贝

  • 浅拷贝 : 浅拷贝又叫浅复制,将对象中的所有字段复制到新的对象(副本)中。其中,值类型字段(java中8中原始类型)的值被复制到副本中后,在副本中的修改不会影响到源对象对应的值。而引用类型的字段被复制到副本中的还是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值做修改会影响到源对象本身。

  • 深拷贝 : 将对象中的所有字段复制到新的对象中。不过,无论是对象的值类型字段,还是引用类型字段,都会被重新创建并赋值,对于副本的修改,不会影响到源对象本身。深拷贝简单归纳就是对象内部引用的对象均复制。

2 使用 = 进行复制操作

package cn.zs.copydemo;

public class Student {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

}

测试

package cn.zs.copydemo;

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setAge(10);
        s1.setName("aaa");

        Student s2 = s1;

        s2.setAge(20);
      //  s1.setAge(20);

        System.out.println("name:"+s1.getName()+" age:"+s1.getAge());
        System.out.println("name:"+s2.getName()+" age:"+s2.getAge());
    }
}
  • 在不添加 s2.setAge(20); s1.setAge(20);是的输出结果是
s1 ------->name:aaa age:10
s2 -------->name:aaa age:10
  • 添加s2.setAge(20)或s1.setAge(20)后输出结果为
s1 ------->name:aaa age:20
s2 -------->name:aaa age:20

= 操作是是一种浅复制,副本或者主体的修改都会相互影响

3. 使用clone方法

3.1 基本类型

package cn.zs.copydemo;

public class Student implements Cloneable {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    @Override
    public Object clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return student;
    }

}

测试

package cn.zs.copydemo;

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setAge(10);
        s1.setName("aaa");

        Student s2 = (Student)s1.clone();

      //  s2.setAge(20);
        s1.setAge(20);
        System.out.println("s1 ------->name:"+s1.getName()+" age:"+s1.getAge());
        System.out.println("s2 -------->name:"+s2.getName()+" age:"+s2.getAge());
    }
}
  • clone 是一种深拷贝,副本与主体的修改互不影响
  • clone 的这种深拷贝特性适用于基本类型,数组和自定义类型只是一种引用

3.2 自定义类型

Address对象

package cn.zs.copydemo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

}

Student对象

package cn.zs.copydemo;

public class Student  {
    private Address address;


    public Address getAddress() {
        return address;
    }

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

测试

package cn.zs.copydemo;

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

        Address address = new Address();
        address.setAddress("ccccccc");

        Student s1 = new Student();
        s1.setAge(10);
        s1.setName("aaa");
        s1.setAddress(address);

        Student s2 = (Student)s1.clone();

        address.setAddress("ddd");


        System.out.println("s1 ------->name:"+s1.getName()+" age:"+s1.getAge()+" address:"+s1.getAddress().getAddress());
        System.out.println("s2 -------->name:"+s2.getName()+" age:"+s2.getAge()+" address:"+s2.getAddress().getAddress());
    }
}
  • addressde 修改会将副本和主体都修改
    那如何避免这种情况?
    1. 为Address添加clone方法
    @Override
    protected Object clone() {
        Address address = null;
        try {
            address = (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return address;

    }
  1. 修改Student的clone方法
    @Override
    public Object clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            student.address =(Address) address.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return student;
    }

3. 拷贝构造函数

将Student的构造函数修改为


    public Student() {

    }

    public Student(Student s) {
        this.age = s.age;
        this.name = s.name;
    }

测试

package cn.zs.copydemo;

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

     Student s1 = new Student();
     s1.setAge(20);
     s1.setName("ssss");

     Student s2 = new Student(s1);

    // s1.setAge(50);
       s2.setAge(50);
        System.out.println("s1 ------->name:"+s1.getName()+" age:"+s1.getAge());
        System.out.println("s2 -------->name:"+s2.getName()+" age:"+s2.getAge());
    }
}
  • 副本和主体之间的修改互不影响
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值