0
点赞
收藏
分享

微信扫一扫

刨析Java中浅拷贝和深拷贝

you的日常 2022-04-14 阅读 64
java

一、前言

拷贝的目的就是为了获得相同的对象,当需要属性值相同的对象时,不需要再重新一步一步创建

在Java中的拷贝需要实现Clonable接口,重写Object的clone()方法;同时在Java中的拷贝也分为浅拷贝和深拷贝,其两者的区别就在于对 对象中引用数据类型的不同处理方法。即:

二、浅拷贝

(一)概念

(二)代码说明

 public class Person implements Cloneable{
    private String name;
    private Integer age;
    public String getName(){
        return name;
    }

    public Integer getAge() {
        return age;
    }

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

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


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

    @Override
    public Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();
}



     public static void test01() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(18);
        Person p2=p1.clone();
        System.out.println(p1+":"+p1.hashCode());
        System.out.println(p2+":"+p2.hashCode());
    }



运行结果:
Person{name='小王', age=18}:1324119927
Person{name='小王', age=18}:1915910607

通过上述代码 我们可以看出拷贝出的Person对象的存储哈希表上的哈希值不一样,说明两个对象的内存位置不同,即成功实现了对象的拷贝。下面的例子将进一步说明成员中引用类型哈希值的变化

Children类:实现Clonable接口

public class Children implements Cloneable{
    private String name;
    private Integer age;
    public String getName(){
        return name;
    }

    public Integer getAge() {
        return age;
    }

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

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

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


}

 Person类 其中存在Children类型的成员变量--->即引用类型变量

public class Person implements Cloneable{
    private String name;
    private Integer age;
    private Children child;
    public String getName(){
        return name;
    }

    public Integer getAge() {
        return age;
    }

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

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

    public void setChild(Children child) {
        this.child = child;
    }

    public Children getChild() {
        return child;
    }

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

    @Override
    public Person clone() throws CloneNotSupportedException {
//        return (Person) super.clone();
        Person clone=(Person)super.clone();//克隆Person对象
        return clone;
    }
}


//以下为测试类

 public static void test02() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(28);
        Children children1=new Children();
        children1.setName("张伟");
        children1.setAge(5);

        p1.setChild(children1);

        Person p2=p1.clone();
        System.out.println(p1+":对象的哈希值"+p1.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
        System.out.println(p2+":对象的哈希值"+p2.hashCode()+":成员变量的哈希值"+p1.getChild().hashCode());
    }

 测试结果:

Person{name='小王', age=28}:对象的哈希值990368553:成员变量的哈希值1096979270
Person{name='小王', age=28}:对象的哈希值2093176254:成员变量的哈希值1096979270

说明 浅拷贝的对象占用不同的内存位置,但引用类型的成员 哈希值一样 ,则说明两对象之间的变量会相互影响。任一个变量的变化会影响到另一个变量。

通过上述的实例,我们归纳以下步骤:

三、深拷贝

(一)概念

 (二)代码说明

对Children类重写clone()方法:

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

对Person重写clone()方法:

   @Override
    public Person clone() throws CloneNotSupportedException {
//        return (Person) super.clone();
        Person clone=(Person)super.clone();//克隆Person对象
        clone.setChild(child.clone()); //克隆Person中的成员变量 通过成员变量child的副本传参
        return clone;
    }

测试类:

 public static void test04() throws CloneNotSupportedException {
        Person p1=new Person();
        p1.setName("小王");
        p1.setAge(28);
        Children children1=new Children();
        children1.setName("张伟");
        children1.setAge(5);
        p1.setChild(children1);

        Person p2=p1.clone(); //克隆person对象 同时也对Children成员变量进行了克隆 即两者完全剥离

        System.out.println(p1.getChild());
        System.out.println(p2.getChild());

        children1.setName("张三");//单独设置children1的属性
        System.out.println(p1.getChild());
        System.out.println(p2.getChild());

        Children children2=p2.getChild();//此时p2为p1的副本 ,用p2调用getChild方法来获取children对象
        children2.setName("张无忌"); //单独设置children2的属性
        System.out.println(p1.getChild());
        System.out.println(p2.getChild());
        //打印出两个子对象的哈希值 两者哈希值不一样说明 两个对象的存储位置不一样
        System.out.println(p1.getChild().hashCode());
        System.out.println(p2.getChild().hashCode());


    }

Children{name='张伟', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张伟', age=5}
Children{name='张三', age=5}
Children{name='张无忌', age=5}
668386784
1329552164

从上述代码可以分析出,对对象进行深拷贝后,改变对象中引用类型数据的值 不会影响到另一个对象,通过最后两行的哈希值也可以比较出 两个子对象的哈希值是不相同的,这样就实现了对象间关系的完全脱离,以免对其他对象的内容造成影响。

深拷贝步骤:

举报

相关推荐

0 条评论