浅拷贝与深拷贝简单介绍

1 浅拷贝

1.1 介绍

浅拷贝会创建一个新对象,新对象属性值有着原对象属性值的准确拷贝。

  • 当属性是基本类型,则直接进行值传递,是两份不同的内容,当对其中一个修改,不会影响另外一个。
    在这里插入图片描述
  • 当属性是引用类型,则拷贝的是该引用类型的内存地址
    -

1.2 实现

Person类

public class Person {

    private String name;

    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Student类:


public class Student implements Cloneable{

    private String name;

    private int age;

    private Person person;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "Student{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                ", person=" + person +
                '}';
    }

    @Override
    protected Object clone(){
        try {
         return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

测试类:

public class ShallowCopyDemo {

    public static void main(String[] args) {

        Person person = new Person("zhangsan",18);

        Student s1 = new Student();
        s1.setPerson(person);
        s1.setName("lisi");
        s1.setAge(19);

        //拷贝
        Student s2 = (Student) s1.clone();
        s2.setPerson(person);
        s2.setName("wangwu");
        s2.setAge(20);

        Person person1 = s2.getPerson();
        person1.setName("zhaoliu");

        System.out.println("s1:  "+s1.toString());
        System.out.println("s2:  "+s2.toString());
    }
}

测试结果:

s1: Student{21685669name=‘lisi’, age=19, person=Person{2133927002name=‘zhaoliu’, age=18}}
s2: Student{1836019240name=‘wangwu’, age=20, person=Person{2133927002name=‘zhaoliu’, age=18}}

根据运行结果,从s1拷贝出来的s2,两者是不同的两个对象,当对两者基本类型修改时,互不影响,相互独立。但对引用类型修改时,修改了一个,则另外一个也会发生修改。

2 深拷贝

2.1 介绍

  • 当属性是基本类型时,其效果与浅拷贝一样。
  • 当属性是引用类型时,会为其单独开辟一块内存空间,让两者存在于不同的内容空间,从而实现相互独立。

2.2 实现

2.2.1 基于Cloneable实现

引用类型的类上需要实现Cloneable接口,并重写clone()
Person类

public class Person implements Cloneable{

    private String name;

    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    protected Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

在拷贝对象上,重写clone()方法,拿到拷贝后产生的新对象,然后对新对象中的引用类型通过clone()重新赋值,从而实现对引用类型深拷贝。

public class Student implements Cloneable{

    private String name;

    private int age;

    private Person person;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "Student{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                ", person=" + person +
                '}';
    }

    @Override
    protected Object clone(){
        try {
            Student student = (Student) super.clone();
            student.person = (Person) person.clone();
            return student;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

测试:

public class DeepCopy {

    public static void main(String[] args) {

        Person person = new Person("zhangsan",18);

        Student s1 = new Student();
        s1.setPerson(person);
        s1.setName("lisi");
        s1.setAge(19);

        //拷贝
        Student s2 = (Student) s1.clone();
        s2.setName("wangwu");
        s2.setAge(20);

        Person person1 = s2.getPerson();
        person1.setName("zhaoliu");

        System.out.println("s1:"+s1.toString());
        System.out.println("s2:"+s2.toString());
    }
}

s1:Student{21685669name=‘lisi’, age=19, person=Person{2133927002name=‘zhangsan’, age=18}}
s2:Student{1836019240name=‘wangwu’, age=20, person=Person{325040804name=‘zhaoliu’, age=18}}

此时可以发现,引用类型没有因为一个改变而影响另一个,因为两个现在是不同的两个对象。

2.2.2 基于序列化实现

通过clone()的方式虽然能够实现,但是问题就是,如果是多级嵌套对象的话,通过这种方式实现来就过于繁琐了。每一个引用类型都是去实现Cloneable接口重写clone()方法。
现在也可以通过对象序列化与反序列化方式来实现深拷贝
Person类:

public class Person implements Serializable {

    private String name;

    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

改造拷贝类,添加构造方法,让引用类型作为构造方法的参数使用
Student类:

public class Student implements Serializable{

    private String name;

    private int age;

    private Person person;

    public Student(String name, int age, Person person) {
        this.name = name;
        this.age = age;
        this.person = person;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Override
    public String toString() {
        return "Student{" +
                this.hashCode()+
                "name='" + name + '\'' +
                ", age=" + age +
                ", person=" + person +
                '}';
    }

}

测试类:

public class DeepCopy {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Person person = new Person("zhangsan",18);

        Student s1 = new Student("lisi",19,person);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(s1);
        oos.flush();

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));

        Student s2 = (Student) ois.readObject();
        s2.setName("wangwu");
        s2.setAge(20);
        Person person1 = s2.getPerson();
        person1.setName("zhaoliu");

        System.out.println("s1:"+s1.toString());
        System.out.println("s2:"+s2.toString());

    }
}

3 小结

深拷贝与浅拷贝的差异性,主要表现在对于引用类型的操作上,当使用浅拷贝,拷贝前与拷贝后对象的引用类型指向的都是同一个内存地址,当修改一个,另一个也会发生改变。而深拷贝,会让两者存在于不同的内存空间,从而实现两者的相互独立,互不影响。
浅拷贝消耗资源较低,但会造成数据不安全。深拷贝解决的数据安全的问题,但消耗大。
在决定使用深拷贝还是浅拷贝时,主要的思考点不在于效率问题,而是取决于当前的业务逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值