专栏首页面朝大海春暖花开java浅拷贝和深拷贝(基础也是很重要的)

java浅拷贝和深拷贝(基础也是很重要的)

对象的copy你兴许只是懵懂,或者是并没在意,来了解下吧。

对于的github基础代码https://github.com/chywx/JavaSE

最近学习c++,跟java很是相像,在慕课网学习c++也算是重温习了下java基础

明白了当初讲师一直强调java传递的话只有值传递,不存在引用传递,为什么一直要重复这,既然只有值传递,为啥还强调不是引用传递

毛病啊这是

 学了c++才知道,原来c++有值传递,引用传递的说法,但是java只是值传递

最简单的理解就是对于方法调用

比如 f(int a,int b) 这是值传递,传递过来的值不会被修改。

再如 f(int &a,int &b)这是引用传递,传递过来的值会被修改

步入正轨,说一说java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。

浅拷贝(Shallow Copy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

通过示例来了解下,

 一:

  使用构造函数实现copy

public class Person {
    public static void main(String[] args) {
        Son s = new Son(10);
        Person p1 = new Person("大海", s);
        Person p2 = new Person(p1);
        p1.setSonName("小海");
        p1.getSon().setAge(12);
        System.out.println("p1:" + p1);// p1:Person [sonName=小海, son=Son [age=10]]
        System.out.println("p2:" + p2);// p2:Person [sonName=大海, son=Son [age=10]]

    }

    private String sonName;
    private Son son;

    // 自定义拷贝函数
    public Person(Person person) {
        this.sonName = person.sonName;
        this.son = person.son;
    }

    public Person(String sonName, Son son) {
        super();
        this.sonName = sonName;
        this.son = son;
    }

    public String getSonName() {
        return sonName;
    }

    public void setSonName(String sonName) {
        this.sonName = sonName;
    }

    public Son getSon() {
        return son;
    }

    public void setSon(Son son) {
        this.son = son;
    }

    @Override
    public String toString() {
        return "Person [sonName=" + sonName + ", son=" + son + "]";
    }

}

class Son {
    private int age;

    public int getAge() {
        return age;
    }

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

    public Son(int age) {
        super();
        this.age = age;
    }

    @Override
    public String toString() {
        return "Son [age=" + age + "]";
    }

}

结果

p1:Person [sonName=小海, son=Son [age=12]] p2:Person [sonName=大海, son=Son [age=12]]

对于上面的实例,该person对象有两个成员,一个基本类型,一个引用类型,结果是拷贝出来的对象,基本类型的那个成员真正的实现了copy。

 二:

  使用自带的clone方法,需要实现cloneable接口,不然会

Exception in thread "main" java.lang.CloneNotSupportedException:

public class Person2 implements Cloneable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Son2 son1 = new Son2(10);

        Person2 person1 = new Person2("大海", son1);
        Person2 person2 = (Person2) person1.clone();
        person2.setSon2Name("小海");
        person2.getSon2().setAge(12);
        System.out.println(person1);
        System.out.println(person2);
    }

    public Person2(String son2Name, Son2 son2) {
        super();
        this.son2Name = son2Name;
        this.son2 = son2;
    }

    private String son2Name;
    private Son2 son2;

    public String getSon2Name() {
        return son2Name;
    }

    public void setSon2Name(String son2Name) {
        this.son2Name = son2Name;
    }

    public Son2 getSon2() {
        return son2;
    }

    public void setSon2(Son2 son2) {
        this.son2 = son2;
    }

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

    @Override
    public String toString() {
        return "Person2 [son2Name=" + son2Name + ", son2=" + son2 + "]";
    }

}

class Son2 {
    private int age;

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son2(int age) {
        super();
        this.age = age;
    }

}

 结果:

Person2 [son2Name=大海, son2=Son2 [age=12]] Person2 [son2Name=小海, son2=Son2 [age=12]]

使用自带的copy实现浅拷贝

---------------------------------------------------------------------------------------------------

深拷贝

  相对于浅拷贝而言,对于引用类型的修改,并不会影响到对应的copy对象的值。每一层的每个对象都进行浅拷贝=深拷贝。

一:

  还是使用clone方法,只不过得手动重写一下。

上代码

public class Person3 implements Cloneable {
    public static void main(String[] args) throws CloneNotSupportedException {
        Son3 son1 = new Son3(10);
        Person3 person1 = new Person3("大海", son1);
        Person3 person2 = (Person3) person1.clone();
        person2.setSon2Name("小海");
        person2.getSon3().setAge(12);//修改对应的引用对象的值。
        System.out.println(person1);
        System.out.println(person2);
    }

    public Person3(String son2Name, Son3 son3) {
        super();
        this.son2Name = son2Name;
        this.son3 = son3;
    }

    private String son2Name;
    private Son3 son3;

    public String getSon2Name() {
        return son2Name;
    }

    public void setSon2Name(String son2Name) {
        this.son2Name = son2Name;
    }

    public Son3 getSon3() {
        return son3;
    }

    public void setSon3(Son3 son3) {
        this.son3 = son3;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person3 clone = (Person3) super.clone();
        clone.setSon3((Son3) clone.getSon3().clone());
        return clone;
    }

    @Override
    public String toString() {
        return "Person3 [son2Name=" + son2Name + ", son3=" + son3 + "]";
    }

}

class Son3 implements Cloneable {
    private int age;

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son3(int age) {
        super();
        this.age = age;
    }

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

}

结果:

Person3 [son2Name=大海, son3=Son2 [age=10]]

Person3 [son2Name=小海, son3=Son2 [age=12]]

方法二:

显然对于多个对象的话,显然就很吃力。可以使用另一种方式,

将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。

public class Person4 implements Serializable {
    public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
        Son4 son = new Son4(10);
        Person4 person1 = new Person4("大海", son);
        //通过序列化方法实现深拷贝
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(person1);
        oos.flush();
        ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Person4 person2=(Person4)ois.readObject();
        person1.setSon4Name("小海");
        person1.getSon4().setAge(12);
        System.out.println(person1.toString());
        System.out.println(person2.toString());
    }

    public Person4(String son4Name, Son4 son4) {
        super();
        this.son4Name = son4Name;
        this.son4 = son4;
    }

    private String son4Name;
    private Son4 son4;

    public String getSon4Name() {
        return son4Name;
    }

    public void setSon4Name(String son4Name) {
        this.son4Name = son4Name;
    }

    public Son4 getSon4() {
        return son4;
    }

    public void setSon4(Son4 son4) {
        this.son4 = son4;
    }

    @Override
    public String toString() {
        return "Person4 [son4Name=" + son4Name + ", son4=" + son4 + "]";
    }
}

class Son4 implements Serializable {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Son2 [age=" + age + "]";
    }

    public Son4(int age) {
        super();
        this.age = age;
    }

}

这是实现序列化接口方案,nice. 

perfect!!!到位

 记录下听得歌曲。

    绝世
            (张克帆)
世间种种的诱惑
不惊不扰我清梦
山高路远不绝我
追踪你绝美的笑容
登高一呼时才懂
始终在为你心痛
俯首对花影摇动
都是东风在捉弄
世间种种的迷惑
都是因你而猜错
水光月光又交融
描述这朗朗的夜空
生死到头的相从
似狂花落叶般从容
当一切泯灭如梦
就在远山被绝世尘封            

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java 记录对象前后修改的内容(工具类)

      RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

    陈灬大灬海
  • java记录对象前后修改的内容(工具类)

      RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。

    陈灬大灬海
  • springMVC接受对象集合,name数组

    这两天开发遇到一个很常见的问题,即使自己一直没遇见过,不过之前看过是实现接受对象集合的代码,只不过没注意罢了

    陈灬大灬海
  • Java 对象的初始化过程_上

    本文主要以白话的形式 ‘简单’ 的描述在 java 中 new 对象的过程,之所以说是 ‘简单’ 的描述是因为,在本文中不会讲述底层的加载过程。

    Melody132
  • Spring Boot 构造器参数绑定,越来越强大了!

    前几天,Spring Boot 2.2.0 正式发布了:Spring Boot 2.2.0 正式发布,支持 JDK 13!,文中有提到基于构造器的参数绑定,那么...

    Java技术栈
  • 不了解这 12 个语法糖,别说你会 Java!

    本文从 Java 编译原理角度,深入字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,帮助大家在学会如何使用 Java 语法糖的同时,...

    Java技术江湖
  • 多个构造器参数使用构建器

    标题一眼看过去可能不是很明白要讲什么,先来看看下面一段代码。 1 package example; 2 3 /** 4 * 重叠构造器 5 * ...

    用户1148394
  • 不懂这12个语法糖,别说你会Java!

    本文从 Java 编译原理角度,深入字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,帮助大家在学会如何使用 Java 语法糖的同时,...

    Java技术江湖
  • 不懂这12个语法糖,别说你会Java!

    本文从 Java 编译原理角度,深入字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,帮助大家在学会如何使用 Java 语法糖的同时,...

    纯洁的微笑
  • 在Java中12个常见的语法糖!

    本文从 Java 编译原理角度,深入字节码及 class 文件,抽丝剥茧,了解 Java 中的语法糖原理及用法,帮助大家在学会如何使用 Java 语法糖的同时,...

    Java3y

扫码关注云+社区

领取腾讯云代金券