• 深拷贝&浅拷贝


    Java中变量有两种类型:基本类型和引用类型

    基本类型的变量保存原始值,即它代表的值就是数值本身 引用类型的变量保存引用值,"引用值"指向内存空间的地址,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置

    注:String类型通过常量赋值时相当于基本数据类型,通过new关键字创建对象时便是引用数据类型

    浅拷贝

    1. 浅拷贝介绍

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

    2. 浅拷贝特点

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

    3. 浅拷贝的实现

    public class Subject {
        private String name;
    
        public Subject(String name) {
            this.name = name;
        }
    
        public String toString() {
            return String.format("[Subject: %d, name: %s]", this.hashCode(), this.name);
        }
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    

      

    public class Student implements Cloneable{
        //基础数据类型
        private int age;
        private String name;
        //引用类型
        private Subject subject;
        public Student(int age,String name,Subject subject){
            this.age=age;
            this.name=name;
            this.subject=subject;
        }
    
        /**
         * 浅拷贝,重写clone()
         * @return
         */
        public Object clone(){
            try {
                //直接调用父类的clone()方法
                return super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        public String toString(){
            return String.format("{Student:%d, subject:%s, name:%s, age:%d}",this.hashCode(),this.subject.toString(),this.name,this.age);
        }
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }
    }
    

      测试

    public class Test {
        public static void main(String[] args) {
            Subject subjectA=new Subject("yuwen");
            Student studentA=new Student(10,"stuA",subjectA);
    
            Student studentB= (Student) studentA.clone();
            studentB.setAge(12);
            studentB.setName("stuB");
    
            Subject subjectB=studentB.getSubject();
            subjectB.setName("shuxue");
    
            System.out.println("studentA: "+studentA.toString());
            System.out.println("studentB: "+studentB.toString());
        }
    }
    

      结果

    studentA: {Student:1896277646, subject:[Subject: 2128227771, name: shuxue], name:stuA, age:10}
    studentB: {Student:396180261, subject:[Subject: 2128227771, name: shuxue], name:stuB, age:12}
    

       studentAstudentB 的基础数据类型的修改互不影响,而引用类型 subject 修改后是会有影响的。

    深拷贝

    1.深拷贝介绍

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

    2. 深拷贝特点

    (1) 对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。 (2) 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。 (3) 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝 (4) 深拷贝相比于浅拷贝速度较慢并且花销较大。

    3.深拷贝的实现

    public class Subject implements Cloneable{
        private String name;
    
        public Subject(String name) {
            this.name = name;
        }
    
        /**
         * 重写clone(),每个对象都调用父类的clone() 方法
         * @return
         */
        public Object clone(){
            try {
                return super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
        
        public String toString() {
            return String.format("[Subject: %d, name: %s]", this.hashCode(), this.name);
        }
    
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    

      

    public class Student implements Cloneable{
        //基础数据类型
        private int age;
        private String name;
        //引用类型
        private Subject subject;
        public Student(int age, String name, Subject subject){
            this.age=age;
            this.name=name;
            this.subject=subject;
        }
    
        /**
         * 深拷贝,重写clone(),每个引用类型的变量都调用 各自重写的clone()
         * @return
         */
        public Object clone(){
            Student student=null;
            try {
                student= (Student) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            student.subject= (Subject) subject.clone();
            return student;
        }
    
        public String toString(){
            return String.format("{Student:%d, subject:%s, name:%s, age:%d}",this.hashCode(),this.subject.toString(),this.name,this.age);
        }
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }
    }
    

      测试

    public class Test {
        public static void main(String[] args) {
            Subject subjectA= new Subject("yuwen");
            Student studentA=new Student(10,"stuA",subjectA);
    
            Student studentB= (Student) studentA.clone();
            studentB.setAge(12);
            studentB.setName("stuB");
    
            Subject subjectB=studentB.getSubject();
            subjectB.setName("shuxue");
    
            System.out.println("studentA: "+studentA.toString());
            System.out.println("studentB: "+studentB.toString());
        }
    }
    

      结果

    studentA: {Student:1896277646, subject:[Subject: 2128227771, name: yuwen], name:stuA, age:10}
    studentB: {Student:396180261, subject:[Subject: 625576447, name: shuxue], name:stuB, age:12}
    

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

    总结

    关于clone()

    JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。

    和 new 的区别

    共同点:都是分配内存,对象都是指向不同的内存地址 不同点:new创建一个对象,clone复制一个对象。new是返回的新对象,而调用clone()方法时,拷贝对象已经包含了一些原来对象的信息,而不是对象的初始信息

    Object类的clone()是一个native方法,native方法的效率一般来说都是远高于Java中的非native方法。这也解释了为 什么要用Objectclone()方法而不是先new一个类,然后把原始对象中的信息赋到新对象中,虽然这也实现了clone功能

    为什么要实现Cloneable接口

    Cloneable接口是不包含任何方法的,其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对 Object类中clone()方法的,如果实现clone()方法的类没有实现Cloneable接口,并调用了Objectclone()方法(也就是调用了 super.clone()方法),那么Objectclone()方法就会抛出CloneNotSupportedException异常

    浅拷贝

    对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝

    深拷贝

    对基本数据类型进行值传递,对引用数据类型,会对引用指向的对象进行拷贝,此为深拷贝。也就是在clone()方法对其内的引用类型的变量再进行一次 clone()

     

    参考

    https://www.jianshu.com/p/e8c6155d9694

    https://www.jianshu.com/p/94dbef2de298

  • 相关阅读:
    Django终端打印SQL语句
    Django之缓存
    Django总结三
    Django之信号
    Django之Form的ModelForm
    git下
    Ajax实现文件的上传
    operator模块
    Django之Form自定义验证规则
    New Concept English Two 32 88
  • 原文地址:https://www.cnblogs.com/yjh1995/p/11573743.html
Copyright © 2020-2023  润新知