zoukankan      html  css  js  c++  java
  • 深拷贝和浅拷贝

    转载自:https://www.jianshu.com/p/94dbef2de298


    1. 浅拷贝

    浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。

    浅拷贝的特点:

    (1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。

    (2) 对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

    浅拷贝的实现:

    实现对象拷贝的类,需要实现 Cloneable 接口,并覆写 clone() 方法。

     1 public class Subject {
     2     private String name;
     3     public Subject(String name) {
     4         this.name = name;
     5     }
     6     public String getName() {
     7         return name;
     8     }
     9     public void setName(String name) {
    10         this.name = name;
    11     }
    12     @Override
    13     public String toString() {
    14         return "[Subject: " + this.hashCode() + ",name:" + name + "]";
    15     }
    16 }
    17 public class Student implements Cloneable {
    18     //引用类型
    19     private Subject subject;
    20     //基础数据类型
    21     private String name;
    22     private int age;
    23     //getters and setters
    24     //...
    25     /**
    26      *  重写clone()方法
    27      * @return
    28      */
    29     @Override
    30     public Object clone() {
    31         //浅拷贝
    32         try {
    33             // 直接调用父类的clone()方法
    34             return super.clone();
    35         } catch (CloneNotSupportedException e) {
    36             return null;
    37         }
    38     }
    39     @Override
    40     public String toString() {
    41         return "[Student: " + this.hashCode() + ",subject:" + subject + ",name:" + name + ",age:" + age + "]";
    42     }
    43 }
    44 45 public class ShallowCopy {
    46     public static void main(String[] args) {
    47         Subject subject = new Subject("yuwen");
    48         Student studentA = new Student();
    49         
    50         studentA.setSubject(subject);
    51         studentA.setName("Lynn");
    52         studentA.setAge(20);
    53         
    54         Student studentB = (Student) studentA.clone();  //浅拷贝
    55         studentB.setName("Lily");
    56         studentB.setAge(18);
    57         Subject subjectB = studentB.getSubject();
    58         subjectB.setName("lishi");
    59         System.out.println("studentA:" + studentA.toString());
    60         System.out.println("studentB:" + studentB.toString());
    61     }
    62 }
    63 64 //输出结果
    65 studentA:[Student: 460141958,subject:[Subject: 1163157884,name:lishi],name:Lynn,age:20]
    66 studentB:[Student: 1956725890,subject:[Subject: 1163157884,name:lishi],name:Lily,age:18]

    通过浅拷贝,studentA和studentB的对象地址不一样(说明浅拷贝生成了一个新的对象),基本数据类型都不一样。但是引用数据类型是一样的,而且引用的对象Subject是同一个对象,说明浅拷贝中只是复制了对象引用的地址。

    2. 对象拷贝

    public static void main(String[] args) {
            Subject subject = new Subject("yuwen");
            Student studentA = new Student();
            studentA.setSubject(subject);
            studentA.setName("Lynn");
            studentA.setAge(20);
            Student studentB = studentA;    //对象拷贝
            studentB.setName("Lily");
            studentB.setAge(18);
            Subject subjectB = studentB.getSubject();
            subjectB.setName("lishi");
            System.out.println("studentA:" + studentA.toString());
            System.out.println("studentB:" + studentB.toString());
    }

    运行结果:

    studentA:[Student: 460141958,subject:[Subject: 1163157884,name:lishi],name:Lily,age:18]
    studentB:[Student: 460141958,subject:[Subject: 1163157884,name:lishi],name:Lily,age:18]

    说明对象拷贝没有生成新的对象,两者的地址是一样的。而浅拷贝生成了一个不一样的对象。

    3. 深拷贝

    深拷贝,在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。

    深拷贝的特点:

    (1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。

    (2) 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。

    (3) 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。

    (4) 深拷贝相比于浅拷贝速度较慢并且花销较大。

    深拷贝的实现:

    对于 Student 的引用类型的成员变量 Subject ,需要实现 Cloneable 并重写 clone() 方法。

    public class Subject implements Cloneable {
        private String name;
        public Subject(String name) {
            this.name = name;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        protected Object clone() throws CloneNotSupportedException {
            //Subject 如果也有引用类型的成员属性,也应该和 Student 类一样实现
            return super.clone();
        }
        @Override
        public String toString() {
            return "[Subject: " + this.hashCode() + ",name:" + name + "]";
        }
    }

    Studentclone() 方法中,需要拿到拷贝自己后产生的新的对象,然后对新的对象的引用类型再调用拷贝操作,实现对引用类型成员变量的深拷贝。

    public class Student implements Cloneable {
    ​
        //引用类型
        private Subject subject;
        //基础数据类型
        private String name;
        private int age;
        
        //getters and setters
        //...
        
        /**
         *  重写clone()方法
         * @return
         */
        @Override
        public Object clone() {
            //深拷贝
            try {
                // 直接调用父类的clone()方法
                Student student = (Student) super.clone();
                student.subject = (Subject) subject.clone();
                return student;
            } catch (CloneNotSupportedException e) {
                return null;
            }
        }
        @Override
        public String toString() {
            return "[Student: " + this.hashCode() + ",subject:" + subject + ",name:" + name + ",age:" + age + "]";
        }
    }
    ​
    public class ShallowCopy {
        public static void main(String[] args) {
            Subject subject = new Subject("yuwen");
            Student studentA = new Student();
            studentA.setSubject(subject);
            studentA.setName("Lynn");
            studentA.setAge(20);
            Student studentB = (Student) studentA.clone();
            studentB.setName("Lily");
            studentB.setAge(18);
            Subject subjectB = studentB.getSubject();
            subjectB.setName("lishi");
            System.out.println("studentA:" + studentA.toString());
            System.out.println("studentB:" + studentB.toString());
        }
    }

    //输出结果
    studentA:[Student: 460141958,subject:[Subject: 1163157884,name:yuwen],name:Lynn,age:20]
    studentB:[Student: 1956725890,subject:[Subject: 356573597,name:lishi],name:Lily,age:18]

    由输出结果可见,深拷贝后,不管是基础数据类型还是引用类型的成员变量,修改其值都不会相互造成影响。

  • 相关阅读:
    Python中re(正则表达式)模块学习
    Django(第一次使用心得,及总结)
    Lunix 安装VMware tools
    主键自动生成办法
    常用的android弹出对话框
    JDBC_mysql---防sql注入,存储图片
    java实现md5加密
    sql语句批量处理Batch
    连接mysql数据库2+操作入门
    Oracle事物基础
  • 原文地址:https://www.cnblogs.com/lyuwalle/p/13944427.html
Copyright © 2011-2022 走看看