Java浅拷贝和深拷贝的区别

浅拷贝和深拷贝的区别

浅拷贝和深拷贝都是复制对象,复制出来的对象,它们的内存地址是重新分配的,修改对象的基本数据类型、包装类型、字符串这些成员变,各对象互不影响。
区别在于
浅拷贝出来的对象,对象中的引用类型和原对象中的引用类型指向同一个内存地址,无论修改哪个对象中的引用类型,都会影响到另一个对象,包括修改引用类型中的基本数据类型、包装类型、字符串和引用类型,
深拷贝出来的对象,对象中的引用类型的内存地址是重新分配的,与原对象的引用类型的数据是互不干扰。

注意: 浅拷贝和深拷贝的最外层对象的地址一定是不同的,最需要的区别是对象中引用类型的地址是否相同。基本数据类型及其包装类型、String类型不算引用类型

注意: 再强调一次,请区分对象中的基本数据类型及其包装类型、String类型,这些不属于引用类型!特别要注意的是,浅拷贝中,对象中的引用类型的地址是同一个内存地址,引用类型中的基本数据类型及其包装类型、String类型的改变会同步到所有浅拷贝对象及原对象中!

浅拷贝的实现

  • 方法一:类要实现Cloneable接口,重写Objectclone方法,在clone方法中调用super.clone()方法即可。
  • 方法二:只要能实现一个对象的所有属性都拷贝到另一个新对象的属性中即可,通常使用方法一
public class ShallowCopy implements Cloneable {
    public ShallowCopy() {
    }
    public ShallowCopy(int age, Integer count, String name, Bean bean) {
        this.age = age;
        this.count = count;
        this.name = name;
        this.bean = bean;
    }
    private int age;
    private Integer count;
    private String name;
    private Bean bean;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "ShallowCopy hash is " + this.hashCode() + " ,{" + "name=" + name + ", count=" + count + ", age='" + age + '\'' + ", bean=" + bean + "}";
    }
}

深拷贝的实现

深拷贝有两种实现方式

  • 方法一:所有自定义类都要实现Cloneable接口,重写Objectclone方法,在对象的clone方法中先调用父类的clone方法生成当前类的新对象,然后调用各个引用类型的clone方法生成各个引用类型的新对象,最后把所有引用类型的对象设置到当前类的新对象中。
  • 方法二:通过对象序列化实现深拷贝。所有引用类型都要实现Serializable接口,各个属性要有settergetter方法,通过ByteArrayOutputStream、ObjectOutputStream、ByteArrayInputStream和ObjectInputStream完成对象的拷贝。
public class DeepCopy implements Serializable {
    public DeepCopy() {
    }
    public DeepCopy(int age, Integer count, String name, Bean bean) {
        this.age = age;
        this.count = count;
        this.name = name;
        this.bean = bean;
    }
    private int age;
    private Integer count;
    private String name;
    private Bean bean;
    @Override
    public String toString() {
        return "DeepCopy hash is " + this.hashCode() + " ,{" + "age=" + age + ", count=" + count + ", name='" + name + '\'' + ", bean=" + bean + '}';
    }
}

上述代码涉及到的类,所有类的setter和getter都省略了

public class Bean implements Serializable {
    public Bean() {
    }

    public Bean(String clazz, int x, Integer y, SubBean subBean) {
        this.clazz = clazz;
        this.x = x;
        this.y = y;
        this.subBean = subBean;
    }

    private String clazz;
    private int x;
    private Integer y;
    private SubBean subBean;

    @Override
    public String toString() {
        return "Bean hash is " + this.hashCode() + " ,{" + "clazz='" + clazz + '\'' + ", x=" + x + ", y=" + y + "} , " + "" + "subBean hash is " + subBean.hashCode();
    }
}
public class SubBean implements Serializable {
}
public class Main {

    public static void main(String[] args) throws Exception {
        print("浅拷贝");
        shallow();
        print();
        print("深拷贝");
        deep();
    }

    public static void print(String title) {
        System.out.println("*********************" + title + "*********************");
    }

    public static void print() {
        System.out.println("");
    }

    public static void deep() throws Exception {
        DeepCopy A = new DeepCopy(18, 99999, "A", new Bean("三年级", 0, 99999, new SubBean()));
        System.out.println(A.toString());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(A);
        oos.flush();
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        DeepCopy B = (DeepCopy) ois.readObject();
        System.out.println(B.toString());
    }

    public static void shallow() throws Exception {
        ShallowCopy A = new ShallowCopy(18, 99999, "A", new Bean("三年级", 0, 99999, new SubBean()));
        print("观察 A 和 B 对象的 hash");
        System.out.println(A.toString());
        ShallowCopy B = (ShallowCopy) A.clone();
        System.out.println(B.toString());
        print();
        print("修改B对象的基本数据类型/String类型,观察 A 和 B 对象的 hash");
        B.setAge(1);
        B.setCount(1);
        B.setName("B");
        System.out.println(A.toString());
        System.out.println(B.toString());
        print();
        print("修改C对象的引用类型中的数据,观察 A、B 和 C 对象的 hash");
        ShallowCopy C = (ShallowCopy) A.clone();
        Bean bean = C.getBean();
        bean.setX(1111111);
        bean.setSubBean(new SubBean());
        System.out.println(A.toString());
        System.out.println(B.toString());
        System.out.println(C.toString());
    }
}

测试结果

注意hash值的变化,上述代码中测试了几种情况

  1. 最外层的对象地址一定是不同的
  2. 修改B对象的基本数据类型/包装类型/String类型,观察 AB 对象的 hash和数据的变化
  3. 修改C对象的引用类型中的数据,观察 ABC 对象的 hash和数据的变化

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值