zoukankan      html  css  js  c++  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!!!到位

     记录下听得歌曲。

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

     

  • 相关阅读:
    初识python 2.x与3.x 区别
    装饰器
    函数的进阶
    Spring Boot启动问题:Cannot determine embedded database driver class for database type NONE
    22.Spring Cloud Config安全保护
    23.Spring Cloud Bus 无法更新问题(踩坑) Spring cloud config server Could not fetch remote for master remote
    24.Spring Cloud之Spring Cloud Config及Spring Cloud Bus
    Spring Boot整合Spring Data Elasticsearch 踩坑
    项目中Spring Security 整合Spring Session实现记住我功能
    32.再谈SpringBoot文件上传
  • 原文地址:https://www.cnblogs.com/chywx/p/9574586.html
Copyright © 2011-2022 走看看