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

昨天同事遇到了一个奇怪的问题,他需要将一个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()方法。

原文地址:https://www.cnblogs.com/ghq120/p/11603961.html

时间: 2024-08-28 07:46:43

Java对象和集合的拷贝/克隆/复制的相关文章

Java对象和集合与Json之间的互相转换

总结一下Java对象和集合与Json之间的互相转换: 1.创建的User类: package com.ghj.packageofdomain; public class User { private int id; private String name; private String gender; public User() { } public User(int id, String name, String gender) { this.id = id; this.name = name

java 对象、集合的非空判断

自我总结,有什么不到位的地方,请各位纠正补充,感激不尽! 目的:使程序更严谨 ***对象验证是否不为空:  if( null != obj ) ***List验证不为空:if( null != list && list.size() > 0 ) ***Map验证不为空:if( null != map && map.size() > 0 ) 好了,废话不多说,上代码 实体类Student(随便起一个) package com.core.test; public c

大数据技术之_27_电商平台数据分析项目_02_预备知识 + Scala + Spark Core + Spark SQL + Spark Streaming + Java 对象池

第0章 预备知识0.1 Scala0.1.1 Scala 操作符0.1.2 拉链操作0.2 Spark Core0.2.1 Spark RDD 持久化0.2.2 Spark 共享变量0.3 Spark SQL0.3.1 RDD.DataFrame 与 DataSet0.3.2 DataSet 与 RDD 互操作0.3.3 RDD.DataFrame 与 DataSet 之间的转换0.3.4 用户自定义聚合函数(UDAF)0.3.5 开窗函数0.4 Spark Streaming0.4.1 Dst

Java对象 json之间的转换(json-lib)

在这里主要简单的介绍一下,如何使用json-lib这个工具包来完成Java对象(或集合)与json对象(或集合)之间的转换~ 1. Java对象转换成json(既创建json) 关键类:JSONObject jsonObject = JSONObject.from(Object obj); 使用说明:只要将Java对象传入方法,那么便可以得到一个JSONObject,然后你便可以直接json.toString();输出json~ 例子: @Test public void testCreateJ

【转】Java如何克隆集合——深度拷贝ArrayList和HashSet

原文网址:http://blog.csdn.net/cool_sti/article/details/21658521 原英文链接:http://javarevisited.blogspot.hk/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html 程序员通常会误用集合类(如List.Set.ArrayList.HashSet)所提供的拷贝构造函数或其它方法来完成集合的拷贝.值得记住的一点是,Java中集合提供的拷贝

java 日志脱敏框架 sensitive-新版本0.0.2-深度拷贝,属性为对象和集合的支持

项目介绍 日志脱敏是常见的安全需求.普通的基于工具类方法的方式,对代码的***性太强.编写起来又特别麻烦. 本项目提供基于注解的方式,并且内置了常见的脱敏方式,便于开发. 用户也可以基于自己的实际需要,自定义注解. 特性 基于注解的日志脱敏 可以自定义策略实现,策略生效条件 常见的脱敏内置方案 java 深拷贝,且原始对象不用实现任何接口. 快速开始 maven 导入 <dependency> <groupId>com.github.houbb</groupId> &l

JAVA 对象拷贝

原文链接: http://blog.csdn.net/jdluojing/article/details/6963112 1.java里的clone分为: A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍. Java中对象的克隆,为了获取对象的一份拷贝,我们可以利用Object类的clone()方法.必须要遵循下面三点 1.在派生类中覆盖基类的clone()方法,并声明为public[Object类中

JAVA对象任意深度克隆clone工具类分享

原文:JAVA对象任意深度克隆clone工具类分享 源代码下载地址:http://www.zuidaima.com/share/1550463408114688.htm package com.zuidaima.n_app.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import jav

Java对象的深复制和浅复制

浅复制与深复制概念 浅复制(浅克隆) :被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. 深复制(深克隆) :被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量.那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象.换言之,深复制把要复制的对象所引用的对象都复制了一遍. Java的clone()方法 (1)clone方法将对象复制了一份并返回给调