浅拷贝-深拷贝总结

本文总结了浅拷贝和深拷贝的区别,包括基本数据类型和引用数据类型的处理方式,浅拷贝主要通过拷贝构造函数和重写clone()方法,而深拷贝则涉及对象序列化。通过实例展示了如何在Java中分别实现这两种复制策略,并强调了深拷贝的复杂性和序列化作为替代方法的应用。
摘要由CSDN通过智能技术生成

浅拷贝-深拷贝总结

浅拷贝:

基本数据类型引用数据类型
值传递成员变量的引用值(内存地址)复制(实际指向同一个)

深拷贝:

基本数据类型引用数据类型
值传递new一个新对象,进行属性赋值

浅拷贝两种实现方法

1、拷贝构造函数
一个学生类,包含两个属性,一个是基本数据类型name,一个是引用数据类型Age

public class Boy {
    String name;
    Age age;

    public Boy() {
    }

    public Boy(String name, Age age) {
        this.name = name;
        this.age = age;
    }
    //拷贝构造函数,实现了对象的拷贝,基本数据类型值传递,引用数据类型内存地址复制
    public Boy(Boy b){
        this.age = b.age;
        this.name = b.name;
    }

    public Age getAge() {
        return age;
    }

    public void setAge(Age age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Boy{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

class Age{
    int age;

    public int getAge() {
        return age;
    }

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

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

    @Override
    public String toString() {
        return "Age{" +
                "age=" + age +
                '}';
    }
}
public class Copyconstructor {
    public static void main(String[] args) {
        Age age = new Age(26);
        Boy boy = new Boy("pmh",age);
        //通过拷贝构造函数实现了对象的浅拷贝
        Boy boy1 = new Boy(boy);
        //我们通过修改其中一个去判断
        boy.name = "zyf";
        age.setAge(99);
        System.out.println(boy);
        System.out.println(boy1);
    }
}

结果

Boy{name='zyf', age=Age{age=99}}
Boy{name='pmh', age=Age{age=99}}

2、重写clone()方法进行浅拷贝
注意点:
1、protected native Object clone() throws CloneNotSupportedException;权限是受保护的,我们无法直接使用
2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException
在这里插入图片描述

步骤如下

1、对象如果想通过clone方法实现浅拷贝,首先需要实现cloneable接口,重写clone()方法

public class Student implements Cloneable {
    String name;
    Score score;

    public Student(String name, Score score) {
        this.name = name;
        this.score = score;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

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

    public Score getScore() {
        return score;
    }

    public void setScore(Score score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

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


class Score{
    int score;

    public Score(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Score{" +
                "score=" + score +
                '}';
    }
}
public class CopyCloneable {
    public static void main(String[] args) {
        Score score = new Score(100);
        Student student = new Student("pmh",score);
        try {
            //由此我们通过实现了Cloneabe的实现类Student重写的clone方法实现了浅拷贝
            Student student1 = (Student)student.clone();
            System.out.println(student);
            System.out.println(student1);
            student.name = "ZYhf";
            score.score = 99;
            System.out.println(student);
            System.out.println(student1);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}

结果

Student{name='pmh', score=Score{score=100}}
Student{name='pmh', score=Score{score=100}}
Student{name='ZYhf', score=Score{score=99}}
Student{name='pmh', score=Score{score=99}}

深拷贝两种实现方法

1、重写clone方法来实现深拷贝
1、假设Student有两个属性,一个基本数据类型name,一个引用数据类型Socre,我们首先需要让Score实现cloneable接口,重写方法clone()

class Score implements Cloneable{
    int score;

    public Score(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Score{" +
                "score=" + score +
                '}';
    }

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

2、然后让Student实现cloneable接口,实现clone方法,通过获取拷贝的Student实例的Score属性重新进行一次拷贝

public class Student implements Cloneable {
    String name;
    Score score;

    public Student(String name, Score score) {
        this.name = name;
        this.score = score;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

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

    public Score getScore() {
        return score;
    }

    public void setScore(Score score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
    @Override
    protected Object clone()  {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
            Student stu = (Student) obj;
         stu.score= (Score) stu.getScore().clone();
        return obj;
    }
}

结果

Student{name='pmh', score=Score{score=100}}
Student{name='pmh', score=Score{score=100}}
Student{name='ZYhf', score=Score{score=99}}
Student{name='pmh', score=Score{score=100}}

虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。
2、通过对象序列化实现深拷贝

class Hobby implements Serializable{
    private String hobby;

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public Hobby(String hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Hobby{" +
                "hobby='" + hobby + '\'' +
                '}';
    }
}
public class Girl implements Serializable{
    private String name;
    private Hobby hobby;

    public String getName() {
        return name;
    }

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

    public Hobby getHobby() {
        return hobby;
    }

    public void setHobby(Hobby hobby) {
        this.hobby = hobby;
    }

    public Girl(String name, Hobby hobby) {
        this.name = name;
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Girl{" +
                "name='" + name + '\'' +
                ", hobby=" + hobby +
                '}';
    }
}
public class CopyWithSerializable {
    public static void main(String[] args) throws Exception {
        Hobby hobby = new Hobby("乒乓球");
        Girl girl1 = new Girl("pmh",hobby);
        //通过序列化方法实现深拷贝
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(girl1);
        oos.flush();
        ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Girl girl2=(Girl)ois.readObject();
        System.out.println(girl1.toString());
        System.out.println(girl2.toString());
        System.out.println();
        //尝试修改stu1中的各属性,观察stu2的属性有没有变化
        girl1.setName("大傻子");
        //改变age这个引用类型的成员变量的值
        hobby.setHobby("羽毛器");
        girl1.setName("216");
        System.out.println(girl1.toString());
        System.out.println(girl2.toString());
    }
}

结果

Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}
Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}
Girl{name='216', hobby=Hobby{hobby='羽毛器'}}
Girl{name='pmh', hobby=Hobby{hobby='乒乓球'}}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值