Java 的深拷贝和浅拷贝学习

1. 为什么需要拷贝

举一个例子,一个Student类,初始化创建一个student01实例,如果想让初始化创建student02实例和student01实例相同,你可能会这样做:Student student02 = student01,直接赋值。这样做是有问题的,student01这个对象实例放在Java堆中,如果你直接赋值,Java堆中并没有创建一个新的实例对象student02,而是让student02变量直接指向Java堆中的student01实例,如果你修改student02 或 student01 中任何一个对象实例,就是修改了Java堆中的那个唯一实例,另外一个对象实例也会随之改变,接下来我们用程序来测试一下。

首先创建一个Student类,代码如下所示:

package clone;

public class Student {
    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;
    }

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

初始化创建一个student01实例,然后通过Student student02 = student01来初始化创建student02实例,修改其中一个,然后查看另外一个的值是否改变。测试代码如下所示:

package clone;

public class MyCloneStudy {
    public static void main(String args[]) {
        Student student01 = new Student();
        student01.setName("syrdbt");
        student01.setAge(21);
        System.out.println(student01);
        Student student02 = student01;
        System.out.println(student02);

        System.out.println("修改student01:");
        student01.setName("Jack");
        student01.setAge(200);
        System.out.println(student01);
        System.out.println(student02);

        System.out.println("修改student02:");
        student01.setName("Rose");
        student01.setAge(18);
        System.out.println(student01);
        System.out.println(student02);
    }
}

运行截图如下所示,显然发生了上述的错误:

2. 浅拷贝

让Studen类实现 Cloneable 接口,Cloneable 接口是一个标识接口,实现了这个接口之后才可以调用Object类的clone方法,然后在Student类中重写clone方法,即可实现浅拷贝。代码如下所示。

Student类实现 Cloneable 接口,重写clone方法。

package clone;

public class Student 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;
    }

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

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


}

测试代码如下所示 ,通过student02 = (Student) student01.clone()来实现浅拷贝。

package clone;

public class MyCloneStudy {
    public static void main(String args[]) {
        Student student01 = new Student();
        student01.setName("syrdbt");
        student01.setAge(21);
        System.out.println(student01);
        Student student02 = null;

        student02 = (Student) student01.clone();

        System.out.println(student02);

        System.out.println("修改student01:");
        student01.setName("Jack");
        student01.setAge(200);
        System.out.println(student01);
        System.out.println(student02);

        System.out.println("修改student02:");
        student01.setName("Rose");
        student01.setAge(18);
        System.out.println(student01);
        System.out.println(student02);
    }
}

运行截图如下所示

3. 深拷贝

浅拷贝有问题吗?显然是有问题的,看下面这个例子,把name这个属性修改成一个类。

Name类代码如下所示:

package clone;

public class Name {
    private String name;

    public Name(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

Student 类如下所示:

package clone;

public class Student implements Cloneable{
    private Name name;
    private int age;

    public Name getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

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

测试代码:

package clone;

public class MyCloneStudy {
    public static void main(String args[]) {
        Name name = new Name("syrdbt");

        Student student01 = new Student();
        student01.setName(name);
        student01.setAge(21);
        System.out.println(student01);
        Student student02 = (Student) student01.clone();
        System.out.println(student02);

        System.out.println("修改Name为Jack:");
        name.setName("Jack");
        System.out.println(student01);
        System.out.println(student02);
    }
}

运行测试代码,你会发现浅拷贝的错误,修改完Name之后,Student01和Student02的name都改变了。

如何解决这个问题,在Student类中将Name成员变量也进行拷贝。

Name 类实现了浅拷贝:

package clone;

public class Name implements Cloneable{
    private String name;

    public Name(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

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

Student 类实现了深拷贝:

package clone;

public class Student implements Cloneable{
    private Name name;
    private int age;

    public Name getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

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

    @Override
    protected Object clone(){
        Student student = null;
        try {
            student = (Student) super.clone();
        } catch (CloneNotSupportedException c) {
            c.printStackTrace();
        }
        student.name = (Name) name.clone();
        return student;
    }
}

测试代码,如下所示:

package clone;

public class MyCloneStudy {
    public static void main(String args[]) {
        Name name = new Name("syrdbt");

        Student student01 = new Student();
        student01.setName(name);
        student01.setAge(21);
        System.out.println(student01);
        Student student02 = (Student) student01.clone();
        System.out.println(student02);

        System.out.println("修改Name为Jack:");
        name.setName("Jack");
        System.out.println(student01);
        System.out.println(student02);
    }
}

运行结果,显然解决了“修改完Name之后,Student01和Student02的name都改变”这个问题。

 

END。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值