Java复制 | Java随笔记

1,338 阅读3分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战


相关文章

Java随笔记:随笔记


前言

  • 将一个对象的引用复制给另外一个对象,一共有三种方式。

    • 直接赋值
    • 浅拷贝
    • 深拷贝
    • 这三种概念实际上都是为了拷贝对象
  • 那么这三种拷贝的区别是什么?

一、直接赋值

  • 在 Java 中,A a1 = a2,我们需要理解的是这实际上复制的是引用,也就是说 a1 和 a2 指向的是同一个对象。因此,当 a1 变化的时候,a2 里面的成员变量也会跟着变化。
  • 感觉这个没啥好说的。。不做案例分析。

二、浅拷贝

  • 创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

  • class Resume implements Cloneable {
        public Object clone() {
            try {
                return (Resume) super.clone();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
  • 自己可以实现Cloneable接口。点进去看下这个super.clone();是啥玩意。

  • image-20211103193352225.png

  • 原来用的是native方法。

    • native方法大家都知道,这玩意不是java写的,只是供Java调用而已。
    • 因为Java程序是运行在JVM虚拟机上面的,要想访问到比较底层的与操作系统相关的就没办法了,只能由靠近操作系统的语言来实现。
  • 因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。

  • 要想对一个对象进行复制,就需要对clone方法覆盖

三、深拷贝

  • 深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。

  • 如果我们一个对象里面的属性是另一个对象怎么办?

    • @Data
      public class teacher {
          private String name;
          private int age;
          private Student student;
      }
      
    • @Data
      class Student implements Cloneable {
          private String name;
          private int age;
      }
      
  • 这种情况下如何进行复制?其实通过重写clone()方法也可以做到深度克隆,但是较麻烦。在此不做介绍。

  • 通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

    • 序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。
    • 通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象。
    • 因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。
  • @Data
    public class Teacher implements Serializable {
        private String name;
        private int age;
        private Student student;
    ​
        public Teacher(String name, int age, Student student) {
            this.name = name;
            this.age = age;
            this.student = student;
        }
    ​
        // 深克隆
        public Object deepClone() throws IOException, ClassNotFoundException {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            return ois.readObject();
        }
    }
    
  • @Data
    @AllArgsConstructor
    public class Student implements Serializable {
        private String name;
        private int age;
    }
    
  • public class test {
        public static void main(String[] args) {
            try {
                Student s = new Student("大鱼", 24);
                Teacher origin = new Teacher("丁老师", 32, s);
                System.out.println("克隆前的学生姓名:" + origin.getStudent().getName());
                Teacher clone = (Teacher) origin.deepClone();
                // 更改克隆后的d学生信息 更改了姓名
                clone.getStudent().setName("我是克隆对象更改后的大鱼2");
                System.out.println("克隆后的学生姓名:" + clone.getStudent().getName());
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    
  • 执行结果:

    • image-20211103195458492.png

路漫漫其修远兮,吾必将上下求索~

如果你认为i博主写的不错!写作不易,请点赞、关注、评论给博主一个鼓励吧~hahah