美文网首页
Java对象和集合的拷贝/克隆/复制

Java对象和集合的拷贝/克隆/复制

作者: 看看你的肥脸 | 来源:发表于2019-09-28 17:18 被阅读0次

昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作。但是他对新的Bean操作后,会影响旧的Bean的值。当听到这个问题的时候,我第一反应就是他的拷贝方法有问题,只是将aBean的内容复制给了bBean,但是在内存中指向的是同一个地址。这里就引出了两个关键词,浅拷贝深拷贝

浅拷贝(浅克隆)

被复制对象的所有变量值都和原来的对象的值相同,但是复制后的对象的引用仍然指向原来的对象。简单来说,就是对A进行拷贝生成B,只是将A的值复制给了B,内存中指向的是同一地址,影响就是改变B的同时,A的值也会改变。

深拷贝(深克隆)

被复制对象的所有变量值都和原来的对象的值相同,除了变量的值改变,也会创建新的指向变量的地址。源对象A和复制后的B,虽然内容是一样的,但是各自指向的地址不同,所以改变相互不受影响。

那问题已经知道,Java的Bean对象要怎么进行深拷贝呢。

Java对象克隆

Java中对象的深克隆

①利用Object类的clone()方法。
②在派生类中重写基类的clone方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口。

这是一个Student的类,重写了clone()方法。

public class Student implements Cloneable {
    private String name;
    private int age;

    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public Object clone() {
        Object o = null;
        try {
            o = (Student)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return o;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}

测试clone

public static void main(String[] args) { 
    Student s1=new Student("张三",18);
    System.out.println("修改前s1值:" + s1.toString());
    
    Student s2=(Student)s1.clone(); 
    s2.setName("李四");
    s2.setAge(20);
    
    //修改学生2后,不影响学生1的值。
    System.out.println("修改后s1值:" + s1.toString());
    System.out.println("s2的值:" + s2.toString());
}

控制台输出的结果如下:

修改前s1值:Student [name=张三, age=18]
修改后s1值:Student [name=张三, age=18]
s2的值:Student [name=李四, age=20]

上面的例子对象中的属性是基本类型,但是如果包含非基本类型,结果怎样呢,上代码,对Student类进行修改,加入Course类。
Student类

public class Student implements Cloneable {
    
    private String name;
    private int age;
    private Course course;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }
    
    public Student(String name, int age, Course course) {
        super();
        this.name = name;
        this.age = age;
        this.course = course;
    }
    
    public Student() {
    }
    
    public Object clone() {
        Object o = null;
        try {
            o = (Student)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return o;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";
    }
    
}

Course类


public class Course {
    
    private String name;
    private int value;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    
    public Course(String name, int value) {
        super();
        this.name = name;
        this.value = value;
    }
    public Course() {
        
    }
    @Override
    public String toString() {
        return "Course [name=" + name + ", value=" + value + "]";
    }
    
}

测试克隆

public static void main(String[] args) { 
    
    Student s1 = new Student();
    s1.setName("张三");
    s1.setAge(24);
    
    Course c = new Course();
    c.setName("语文");
    c.setValue(80);
    
    s1.setCourse(c);
    System.out.println("修改前s1值:" + s1.toString());
    
    Student s2 = (Student)s1.clone();
    s2.setName("李四");
    s2.setAge(20);
    
    Course c2 = s2.getCourse();
    c2.setName("数学");
    c2.setValue(90);
    
    //修改学生2的Course后,影响学生1的Course。
    System.out.println("修改后s1值:" + s1.toString());
    System.out.println("s2的值:" + s2.toString());
}

控制台输出结果

修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
修改后s1值:Student [name=张三, age=24, course=Course [name=数学, value=90]]
s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]
上面的例子说明调用clone方法,拷贝原始对象中的内容,对于基本数据类型,这样的操作是没有问题的,但是对于非基本类型,它们保存的仅仅是对象的引用。

为了解决上面的问题,我们需要使用深度克隆方案。修改之后的Student类和Course类如下
Student类

public class Student implements Cloneable {
    
    private String name;
    private int age;
    private Course course;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Course getCourse() {
        return course;
    }
    public void setCourse(Course course) {
        this.course = course;
    }
    
    public Student(String name, int age, Course course) {
        super();
        this.name = name;
        this.age = age;
        this.course = course;
    }
    
    public Student() {
    }
    
    public Student clone() {
        Student s = null;
        try {
            s = (Student)super.clone();
            s.course = course.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return s;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", course=" + course + "]";
    }
    
}

Course类


public class Course implements Cloneable{
    
    private String name;
    private int value;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getValue() {
        return value;
    }
    public void setValue(int value) {
        this.value = value;
    }
    
    public Course(String name, int value) {
        super();
        this.name = name;
        this.value = value;
    }
    public Course() {
        
    }
    
    public Course clone() {
        Course c = null;
        try {
            c = (Course)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        return c;
    }
    @Override
    public String toString() {
        return "Course [name=" + name + ", value=" + value + "]";
    }
    
}

测试方法使用之前的方法,下面的运行后的结果。

修改前s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
修改后s1值:Student [name=张三, age=24, course=Course [name=语文, value=80]]
s2的值:Student [name=李四, age=20, course=Course [name=数学, value=90]]

根据结果可知,通过深度克隆后,clone后的对象非基本类的变量修改,不会对原对象造成影响。

对于集合的Clone操作也一样,集中的属性如果是基本数据类型的话,循环赋值,或者使用addAll()方法都不会对原集合造成影响。若集合中存放了非基本数据类型的话,如上述中的Student对象,就必须对Student对象添加重写clone()方法。

相关文章

  • Java对象和集合的拷贝/克隆/复制

    昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作。但是他对新的B...

  • java 对象的拷贝

    拷贝:即复制 对象拷贝:即对象复制 java 对象拷贝分类:浅拷贝、深拷贝 java 对象的浅拷贝和深拷贝针对包含...

  • 理解Java浅克隆和深克隆

    克隆概念 Java一切皆对象,克隆就是对对象的克隆;克隆可能听起来有点高级,也可以为对象复制或者对象拷贝。平时开发...

  • java克隆

    java克隆 java克隆分为浅克隆和深克隆,概念如下: 浅拷贝(浅克隆)克隆出来的对象的所有变量都含有与原来的对...

  • Java深复制浅复制解析.md

    Java 克隆概念 Java克隆分为深克隆和浅克隆两种类型。 浅复制(浅克隆)被复制对象的所有变量都含有与原来的对...

  • 深复制和浅复制

    1、浅复制是指针拷贝,深复制是内容拷贝 2、不管是集合类对象,还是非集合类对象,接收到copy和mutableCo...

  • C# 正确实现浅拷贝和深拷贝

    为对象创建副本的技术称为拷贝(也叫克隆)。我们将拷贝分为浅拷贝和深拷贝。 浅拷贝 将对象中的所有字段复制到新的对...

  • iOS 集合的深复制与浅复制

    iOS 集合的深复制与浅复制 概念 对象拷贝有两种方式:浅复制和深复制。顾名思义,浅复制,并不拷贝对象本身,仅仅是...

  • Java 之浅拷贝、深拷贝,你到底知多少?

    在 Java 开发中,对象拷贝或者说对象克隆是常有的事,对象克隆最终都离不开直接赋值、浅拷贝、深拷贝 这三种方式,...

  • Object的克隆

    克隆一个对象 浅克隆 浅克隆(也叫做浅拷贝)仅仅复制了这个对象本身的成员变量,该对象如果引用了其他对象的话,也不对...

网友评论

      本文标题:Java对象和集合的拷贝/克隆/复制

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