理解Java对象浅拷贝和深拷贝以及实现深拷贝的三种方式

本文介绍了Java中浅拷贝和深拷贝的概念,通过代码示例展示了浅拷贝如何导致原始对象和拷贝对象间的属性共享。并详细解释了实现深拷贝的三种方法:直接新建对象、调用父类clone方法以及通过序列化和反序列化。最后,讨论了Java中Object.clone()方法默认为浅拷贝以及深拷贝在处理复杂对象时的重要性。
摘要由CSDN通过智能技术生成

理解浅拷贝和深拷贝

代码演示浅拷贝

先看一段代码:
worker.java

/**
 * <h1>员工</h1>
 * */
@Data
public class Worker implements Cloneable {

    private String name;
    private Integer age;
    private String gender;

    private EducationInfo educationInfo;

    public Worker(String name, Integer age, String gender, String school, String time) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.educationInfo = new EducationInfo(school, time);
    }

    @Override
    public Object clone() {

        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            return null;
        }
    }
}

EducationInfo.java

/**
 * <h1>教育信息</h1>
 * */
@Data
@AllArgsConstructor
public class EducationInfo implements Cloneable*/{

    private String school;

    private String time;

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

Main.java测试克隆代码

/**
* <h1>理解深拷贝和浅拷贝</h1>
* */
@SuppressWarnings("all")
public class Main {
   private static void copyTest() {

       Worker worker1 = new Worker(
               "lcry", 22, "m", "CSDN大学", "2021"
       );
       System.out.println("原始对象: " + worker1.getEducationInfo().getSchool());

       Worker worker2 = (Worker) worker1.clone();
       System.out.println("拷贝对象: " + worker2.getEducationInfo().getSchool());

       worker2.getEducationInfo().setSchool("社会大学");

       System.out.println("原始对象: " + worker1.getEducationInfo().getSchool());
       System.out.println("拷贝对象: " + worker2.getEducationInfo().getSchool());
   }

   public static void main(String[] args) throws CloneNotSupportedException {
       copyTest();
   }
}

执行结果可想而知,当我们修改了work2的school属性值,发现work1的school属性值也变了,这就是浅拷贝,也同时说明Object类自带的clone方法是浅拷贝

图解浅拷贝深拷贝

看下图更加清晰理解。
深拷贝和浅拷贝

实现深拷贝三种方式

可以有三种方式。我们按照前面的案例进行改造代码word类如下:

/**
 * <h1>员工</h1>
 * */
@Data
public class Worker implements Serializable {

    private String name;
    private Integer age;
    private String gender;

    private EducationInfo educationInfo;

    public Worker(String name, Integer age, String gender, String school, String time) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.educationInfo = new EducationInfo(school, time);
    }
    
//    @Override
//    public Object clone() {
//
//        // 第一种方式:直接通过new对象创建新的对象
        Worker worker = new Worker(
                name, age, gender, educationInfo.getSchool(), educationInfo.getTime()
        );
        return worker;
//
//        // 第二种方式:通过父类clone再进行赋值
//        try {
//            Worker worker = (Worker) super.clone();
//            worker.educationInfo = (EducationInfo) educationInfo.clone();
//            return worker;
//        } catch (CloneNotSupportedException ex) {
//            return null;
//        }
//    }

//         推荐第三种方式:通过序列化和反序列化使用流进行深拷贝,注意类都要实现Serializable接口
    public Worker clone() {

        Worker worker = null;

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            // 将流序列化成对象
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            worker = (Worker) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return worker;
    }
}

总结

  • Java 中 Object 中的 clone 方法默认是浅拷贝,针对引用类型执行的是同一个地址;
  • 实现深拷贝的三种方式:
    1. 第一种方式:直接通过 new 对象创建新的对象,通过 new 出来的对象肯定是在内存中重新开辟一块空间存储所以可以实现深拷贝;
    2. 第二种方式:通过调用父类clone再进行重新复制,虽然调用父类 Native 修饰的 clone 方法比第一种方式速度快,此步骤如果继承类中有多个引用类型克隆相对麻烦;
    3. 第三种方式:通过序列化和反序列化使用流进行深拷贝(注意类都要实现 Serializable 接口),因为保存在流中的数据相当于新的,若要实现对象深拷贝,推荐使用此方式。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值