zoukankan      html  css  js  c++  java
  • java中的浅拷贝和深拷贝解析

    任何编程语言中,其实都有浅拷贝和深拷贝的概念,java中也不例外。在对一个现有的对象进行拷贝操作的时候,是有浅拷贝和深拷贝之分的,他们在实际使用中,区别很大,如果对其进行混淆,可能会引发一些难以排查的问题。

    本文就在java中的浅拷贝和深拷贝做一个详细的解说。

    什么是浅拷贝和深拷贝?

    首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。

    在java中,除了基本数据类型(元类型)之外,还存在类的实例对象这个引用数据类型。而一般使用【=】号做赋值操作的时候。对于基本数据类型,实际上拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向同一个对象。

    而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。

    所以到现在,就应该了解了,所谓浅拷贝和深拷贝,只是在拷贝对象的时候,对类的实例对象这种引用数据类型的不同操作而已。

    总结来说:

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

    febeaT.md.png

    2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

    feb1MR.md.png

    从内存角度区分浅拷贝和深拷贝的区别

    • 数据分为基本数据类型和引用数据类型。基本数据类型:数据直接存储在栈;引用数据类型:存储在栈中的是对象的引用地址,真实的对象数据存放在堆内存里。
    • 浅拷贝:对于基本数据类型:直接复制数据值;对于引用数据类型:只是复制了对象的引用地址,新旧对象指向同一个内存地址,修改其中一个对象的值,另一个对象的值随之改变。
    • 深拷贝:对于基础数据类型:直接复制数据值;对于引用数据类型:开辟新的内存空间,在新的内存空间里复制一个一模一样的对象,新老对象不共享内存,修改其中一个对象的值,不会影响另一个对象的值。
    • 深拷贝相比较于浅拷贝速度较慢并且花销较大。

    浅拷贝和深拷贝案例分析

    • 浅拷贝实现Cloneable,深拷贝是通过实现Serializable读取二进制流

    深拷贝实现

    首先Person对象实现Serializable接口,然后自定义深拷贝方法deepClone()

    /**
    * 深拷贝
    * @return Person 注意 要实现序列化接口
    */
    public Person deepClone(){
    	try {
                //输出(序列化)
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(this);
                //输入(反序列化)
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                ObjectInputStream ois=new ObjectInputStream(bais);
                Person person=(Person) ois.readObject();
                return person;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }        
    }
    

    接下来验证一下深拷贝是否成功:

    @Test
    public void testProtoType(){
    	Person person1=new Person();
        person1.setUsername("wcc");
        person1.setAge(20);
        //初始化list 并为其加入数据
    	person1.setList(new ArrayList<>());
        person1.getList().add("aaa");
        person1.getList().add("bbb");
        System.out.println(person1);
    
        //深拷贝
        Person person=person1.deepClone();
        person.setUsername("hzw");
        //给person中的list添加一条数据
        person.getList().add("ccc");
        System.out.println("person:"+person);
        System.out.println("person1:"+person1);
        boolean flag1=person1==person;
        System.out.println("person1和person的引用地址是否相同:"+flag1);
        boolean flag2=person1.getList()==person.getList();
        System.out.println("person1和person的list引用地址是否相同:"+flag2);
    }
    

    输出结果如下:

    Person{username='wcc', age=20, list=[aaa, bbb]}
    person:Person{username='hzw', age=20, list=[aaa, bbb, ccc]}
    person1:Person{username='wcc', age=20, list=[aaa, bbb]}
    person1和person的引用地址是否相同:false
    person1和person的list引用地址是否相同:false
    

    由结果可得出:深拷贝person所得到的list内存地址和原来的person1中的内存地址都是不同的,深拷贝成功。

  • 相关阅读:
    linux学习之路7 linux下获取帮助
    51nod 1002 数塔取数问题
    51nod 1002 数塔取数问题
    51nod 1001 数组中和等于K的数对
    51nod 1001 数组中和等于K的数对
    linux学习之路6 Vi文本编辑器
    linux学习之路6 Vi文本编辑器
    计算误差——ACM计算几何中的精度问题
    计算误差——ACM计算几何中的精度问题
    daily_journal_3 the game of thrones
  • 原文地址:https://www.cnblogs.com/gesh-code/p/15246798.html
Copyright © 2011-2022 走看看