集合里的深拷贝和浅拷贝

作者: 猪_队友 | 来源:发表于2018-04-21 11:56 被阅读104次

浅拷贝(浅克隆):

复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

深拷贝(深克隆):

复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

其实本质上的区别就是一个是指针的复制,一个是指针背后真正数据的复制。因为java弱化了指针的定义,所以很多人对这个不太了解,大家可以看一下指针的定义和使用,然后在理解这个就容易了。我也给大家画几个价值千金的图来说明一下。


image.png

就好比我们

 Student s1 =new Student("张三");
 Student s2 =new Student("李四");
                s2 = s1;
                s1.name = "王五";
 System.out.println(s2.name);

结果输出的是:王五。


image.png

浅拷贝就是引用的复制,其实内存还是一个内存,改变两个的其中一个都是改变堆内存中的对象实体。
而深拷贝就是在堆内存中复制一份,再由被引用。所以两个引用就是完全独立的,更改是不会影响的。
深拷贝:

public class Student implements Cloneable{  
    
    private String name;  
      
    public Student( String name) {  
   
        this.name = name;  
    }  

    public String getName() {  
        return name;  
    }  
      
    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        return (Student)super.clone();  
    }  
}  


   Student s1 = new Student("张三");
        Student s2 = new Student("李四");
//
        try {
            s2 = s1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        s1.name = "王五";
        System.out.println(s2.name);

输出:张三。


image.png

需要注意的是:如果对象里面有其他的对象,每一个对象都需要调用实现Cloneable接口,重写clone();我们来看一下对象里面嵌套对象。

 static class Student implements Cloneable {
        String name;
        Course course;

        public Student(String name, Course course) {
            this.name = name;
            this.course = course;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Course getCourse() {
            return course;
        }

        public void setCourse(Course course) {
            this.course = course;
        }

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

    static class Course {
        String course_name;
        int count;
//        

        public Course(String course_name, int count) {
            this.course_name = course_name;
            this.count = count;
        }

        public String getCourse_name() {
            return course_name;
        }

        public void setCourse_name(String course_name) {
            this.course_name = course_name;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }
    }


main:
 Student s1 = new Student("张三",new Course("语文",2));
        Student s2 = null;
        try {
            s2 = s1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        s1.course.course_name = "英语";
        System.out.println(s2.getCourse().getCourse_name() );
        System.out.println("s2==s1 :"+(s2==s1 ));
        System.out.println("s2.getCourse()==s1.getCourse() :"+(s2.getCourse()==s1.getCourse() ));
        System.out.println("s2.getCourse().getCourse_name()==s1.getCourse().getCourse_name() :"+(s2.getCourse().getCourse_name()==s1.getCourse().getCourse_name() ));

   

输出:
英语
s2==s1 :false
s2.getCourse()==s1.getCourse() :true
s2.getCourse().getCourse_name()==s1.getCourse().getCourse_name() :true
还是画图说明一下吧。


image.png

那么我们让Course也实现clone

 static class Course implements Cloneable{
        String course_name;
        int count;
//

        public Course(String course_name, int count) {
            this.course_name = course_name;
            this.count = count;
        }

        public String getCourse_name() {
            return course_name;
        }

        public void setCourse_name(String course_name) {
            this.course_name = course_name;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }
    }

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

那结果又是什么呢?
输出:

英语
s2==s1 :false
s2.getCourse()==s1.getCourse() :true
s2.getCourse().getCourse_name()==s1.getCourse().getCourse_name() :true

结果可能出乎了大家的意料,为何呢》那是因为你没有真正调用Course的clone方法。

  @Override
        protected Student clone() throws CloneNotSupportedException {
            Student s = (Student) super.clone();
            s.course = (Course) this.getCourse().clone();
            return s;


        }

这样就OK了
输出:

语文
s2==s1 :false
s2.getCourse()==s1.getCourse() :false
s2.getCourse().getCourse_name()==s1.getCourse().getCourse_name() :false

最后我们看看这样在集合里是否生效

  
        ArrayList<Student> students = new ArrayList<>();
        ArrayList<Student> students_copy = new ArrayList<>();
        Student s11 = new Student("张三1", new Course("语文1", 1));
        Student s12 = new Student("张三2", new Course("语文2", 2));
        Student s13 = new Student("张三3", new Course("语文3", 3));
        students.add(s11);
        students.add(s12);
        students.add(s13);
        students_copy.addAll(students);


        for(int i = 0;i<students_copy.size();i++){
          System.out.println("students_copy:"+students_copy.get(i).getCourse().getCourse_name());
            System.out.println("students:"+students.get(i).getCourse().getCourse_name());
        }

输出:

students_copy:语文1
students:语文1
students_copy:语文2
students:语文2
students_copy:语文3
students:语文3

看出来什么问题了吗?
是滴,我们没有Clone,改一下


        ArrayList<Student> students = new ArrayList<>();
        ArrayList<Student> students_copy = new ArrayList<>();
        Student s11 = new Student("张三1", new Course("语文1", 1));
        Student s12 = new Student("张三2", new Course("语文2", 2));
        Student s13 = new Student("张三3", new Course("语文3", 3));
        students.add(s11);
        students.add(s12);
        students.add(s13);
                for(int i = 0;i<students.size();i++){
            students_copy.add(students.get(i).clone());
            students.get(i).getCourse().setCourse_name("英语"+i);
        }


        for(int i = 0;i<students_copy.size();i++){
          System.out.println("students_copy:"+students_copy.get(i).getCourse().getCourse_name());
            System.out.println("students:"+students.get(i).getCourse().getCourse_name());
        }

输出:

students_copy:语文1
students:英语0
students_copy:语文2
students:英语1
students_copy:语文3
students:英语2

也是生效的,很多资料里之所以说集合里面的不生效,大概是没有完全clone();但是我们也看到了这样做实在是麻烦,特别是 对象十分大而且复杂,这样克隆很容易出错误,怎么办呢?

 public static <T> List<T> deepCopy(List<T> src) {
        List<T> dest = null;
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(src);
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream in = new ObjectInputStream(byteIn);
            dest = (List<T>) in.readObject();
        } catch (IOException e) {

        } catch (ClassNotFoundException e) {

        }
        return dest;
    }

通过IO流是个不错的方法,没有了上面的麻烦操作,但是记得实现Serializable接口哈。
其实还有一件事,就是网上的文章良莠不齐,很多都是copy,没有验证,所以大家在查资料的时候一定要亲自试一试,当然我可能有很多错误,同时希望可以得到大家指正。

相关文章

  • 17.是否了解 深拷贝 和 浅拷贝 的概念,集合类深拷贝如何实现

    深拷贝内存拷贝 浅拷贝指针拷贝 浅拷贝 深拷贝 集合的浅复制 (shallow copy) 集合的浅复制有非常多种...

  • 9总 函数的基础

    复习: 列表,字典,元祖,集合 1.浅拷贝和深拷贝: import copy copy.copy(对象):浅拷贝 ...

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • 集合里的深拷贝和浅拷贝

    浅拷贝(浅克隆): 复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

  • python five day

    深浅拷贝浅拷贝只copy一层,深拷贝完全拷贝 shallow copy Deep copydeepcopy 集合 ...

  • iOS - copy 与 mutableCopy

    一说到拷贝,就不得不提浅拷贝和深拷贝。 何谓浅拷贝?何谓深拷贝? 往简单的说: 浅拷贝:拷贝地址。 深拷贝:拷贝内...

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • iOS--拷贝相关题

    1、什么是深拷贝什么是浅拷贝?浅拷贝和深拷贝的区别 * 浅拷贝(shallow copy):指针拷贝,对于被拷贝对...

  • copy和mutableCopy的区别

    copy和mutableCopy的区别 深拷贝和浅拷贝的区别 在OC中对象的拷贝方式有两种:深拷贝和浅拷贝.浅拷贝...

网友评论

    本文标题:集合里的深拷贝和浅拷贝

    本文链接:https://www.haomeiwen.com/subject/bbwokftx.html