美文网首页
Java 深浅拷贝

Java 深浅拷贝

作者: PC_Repair | 来源:发表于2020-08-25 17:20 被阅读0次

浅拷贝定义:

  • 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。

  • 简而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象

深拷贝定义:

  • 深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

  • 简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。

"=" 的作用:

  • 基本类型:拷贝数据的值

  • 其他类型:拷贝地址的引用,拷贝出的新对象与原对象共享实例变量,不受访问权限影响。

  • String 类型:拷贝的也是一个引用,但其内容存储在字符串池中,修改会重新生成新的字符串,原有字符串内容是保持不变的(String 是不可变的),等同于基本类型。

浅拷贝

浅拷贝就是直接使用 "=" 给基本类型赋值(即拷贝引用)。

List<String> srcList = new ArrayList<>();
srcList.add("android");
List<String> cpyList = srcList;
srcList.add("ios");
  • 输出这两个list,srcList和cpyList都有android,ios两项。
深拷贝

深拷贝就是将所有属性均拷贝到另外一个对象中,将其中任何一个对象任何一个属性发生变化时,另外一个对象不受任何影响。

List<String> srcList = new ArrayList<>();
srcList.add("android");
List<String> cpyList = new ArrayList<>(srcList);
srcList.add("ios");
  • 输出这两个list,srcList有android,ios两项,而cpyList只有android一项。

深拷贝实现

(1)clone 实现深拷贝

每个对象都是继承于 Object 类,Object 类提供了 clone() 方法,通过实现 Cloneable 接口可以使该具有拷贝的能力,拷贝的操作是在内存中进行的,所以性能会比直接构造对象要快速很多

public class DeepCopyByClone {

    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("Yao");
        s1.setTeacher(new Teacher("Kobe"));
        Student s2 = s1.clone();
        s2.setName("Yi");
        s2.getTeacher().setName("Jordan");
        System.out.println(s1.getName() + "'s teacher is "
                + s1.getTeacher().getName());
        System.out.println(s2.getName() + "'s teacher is "
                + s2.getTeacher().getName());
    }

}

class Student implements Cloneable {
    private String name;
    private Teacher teacher;

    public String getName() {
        return name;
    }

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

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    protected Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            student.setTeacher(student.getTeacher());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return student;
    }
}

class Teacher {
    private String name;

    public String getName() {
        return name;
    }

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

    public Teacher(String name) {
        this.name = name;
    }
}
  • 输出
Yao's teacher is Jordan
Yi's teacher is Jordan
  • 图片分析
image-20200825165912535.png

这里关于teacher的拷贝是通过=号来操作的,仅仅实现了浅拷贝。以下的 clone() 方法的修改将实现深拷贝。

    @Override
    protected Student clone() {
        Student student = null;
        try {
            student = (Student) super.clone();
            //student.setTeacher(student.getTeacher());
            student.setTeacher(new Teacher(student.getTeacher().getName()));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return student;
    }
  • 输出
Yao's teacher is Kobe
Yi's teacher is Jordan
  • 图片分析
image-20200825170000030.png

(2)对象序列化实现深拷贝

通过对象序列化,使用 writeObjectreadObject 也可以实现对象的深拷贝。

把对象写到流里的过程是序列化过程Serialization),而把对象从流中读出来的过程则叫做反序列化过程Deserialization)。

应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

import java.io.*;

public class CloneUtils {

    @SuppressWarnings("unchecked")
    public static Object clone(Object obj) {
        Object cloneObj = null;
        try {
            //写入字节流
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream obs = new ObjectOutputStream(out);
            obs.writeObject(obj);
            obs.close();

            //分配内存,写入原始对象,生成新对象
            ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(ios);

            //返回生成的新对象
            cloneObj = ois.readObject();
            ois.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return cloneObj;
    }

    public static void main(String[] args) {
        Student2 s1 = new Student2();
        s1.setName("Yao");
        s1.setTeacher(new Teacher2("Kobe"));
        Student2 s2 = (Student2) CloneUtils.clone(s1);
        s2.setName("Yi");
        s2.getTeacher().setName("Jordan");
        System.out.println(s1.getName() + "'s teacher is "
                + s1.getTeacher().getName());
        System.out.println(s2.getName() + "'s teacher is "
                + s2.getTeacher().getName());
    }
}

class Student2 implements Serializable {
    private String name;
    private Teacher2 teacher;

    public String getName() {
        return name;
    }

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

    public Teacher2 getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher2 teacher) {
        this.teacher = teacher;
    }
}

class Teacher2 implements Serializable {
    private String name;

    public String getName() {
        return name;
    }

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

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

参考文章:

相关文章

  • Java深浅拷贝

    浅拷贝 浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象 输出结果 两个引用student1和student2指...

  • Java 深浅拷贝

    浅拷贝定义: 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的...

  • Java 最近遇到的面试题

    JAVA 基础 java 对象拷贝深浅拷贝 对象何时进入老年代 Minor GC 和 Full GC 有什么不同 ...

  • Java之深浅拷贝

    Java之深浅拷贝 基本类型:拷贝数据的值其他类型:拷贝地址的引用,拷贝出的新对象与原对象共享实例变量,不受访问权...

  • (13)Java深浅拷贝

    引用拷贝(一个人,不同名字) 浅拷贝(双胞胎):创建对象,将目标对象内容复制过来,不直接拷贝引用 深拷贝:全独立原...

  • 2018-08-29

    深浅拷贝 1.根据拷贝内容的不同,分为深浅拷贝 深拷贝:内容...

  • Java中创建对象的方式

    一:Java中创建对象的方式 示例 注:同步更新于CreateObjectTest 二:Java的深浅拷贝 三:如...

  • js的深浅拷贝

    js的深浅拷贝可以分为数组的深浅拷贝和对象的深浅拷贝 一、数组的深浅拷贝如果只是简单的将数组中的元素付给另外一个数...

  • Python—浅拷贝与深拷贝

    浅拷贝 深拷贝 深浅拷贝的作用

  • 深浅拷贝

    先来了解一下这些:在js中变量类型基本分为两种:基本数据类型和引用数据类型;基本类型:Underfied Null...

网友评论

      本文标题:Java 深浅拷贝

      本文链接:https://www.haomeiwen.com/subject/yrpzjktx.html