昨天同事遇到了一个奇怪的问题,他需要将一个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对象和集合的拷贝/克隆/复制的更多相关文章

  1. Json——使用Json jar包实现Json字符串与Java对象或集合之间的互相转换

    总结一下利用Json相关jar包实现Java对象和集合与Json字符串之间的互相转换: 1.创建的User类: package com.ghj.packageofdomain; public clas ...

  2. 如何复制一个java对象(浅克隆与深度克隆)

    在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...

  3. java 对象、集合的非空判断

    自我总结,有什么不到位的地方,请各位纠正补充,感激不尽! 目的:使程序更严谨 ***对象验证是否不为空:  if( null != obj ) ***List验证不为空:if( null != lis ...

  4. java 对象 json 集合 数组 互转

    1.先定义一个类对象 package com.basics; import com.alibaba.fastjson.JSONObject; import java.util.List; import ...

  5. Java 对象复制

    Java 对象的一共有 3 种复制对象的方式. 1.直接赋值 (引用复制 ),此种复制方式比较常用. 诸如 A  a = b ;  a 是直接复制了b的引用 ,也就是说它俩指向的是同一个对象. 此时 ...

  6. 将java的对象或集合转成json形式字符串

    将java的对象或集合转成json形式字符串: json的转换插件是通过java的一些工具,直接将java对象或集合转换成json字符串. 常用的json转换工具有如下几种: 1)jsonlib 需要 ...

  7. 大数据技术之_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 ...

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

    在这里主要简单的介绍一下,如何使用json-lib这个工具包来完成Java对象(或集合)与json对象(或集合)之间的转换~ 1. Java对象转换成json(既创建json) 关键类:JSONObj ...

  9. c++类与对象(1)——构造,复制构造函数

    CPP的类与对象: 当我们定义一个基本类型变量时,方法如下: int p; #定义一个int类型变量 bool b; #定义一个bool类型变量 float c ; #定义一个float类型变量 显然 ...

随机推荐

  1. 《设计模式之美》 <02>评判代码质量好坏的维度

    如何评价代码质量的高低? 实际上,咱们平时嘴中常说的“好”和“烂”,是对代码质量的一种描述.“好”笼统地表示代码质量高,“烂”笼统地表示代码质量低.对于代码质量的描述,除了“好”“烂”这样比较简单粗暴 ...

  2. Hadoop_12_Hadoop 中的RPC框架演示

    Hadoop中自己提供了一个RPC的框架.集群中各节点的通讯都使用了那个框架 1.服务端 1.1.业务接口:ClientNamenodeProtocol package cn.bigdata.hdfs ...

  3. day_03比特币转账的运行原理

    在2008年全球经济危机中,中本聪想如果能构建一个没有中心机构的货币发行体系,货币就不会被无限发行,大家都很公平公正,于是中本聪构建了比特币这样一个体系: 一.非中心化下的比特币发行机制 比特币的发行 ...

  4. TF_Variable Sharing

    Reference: http://jermmy.xyz/2017/08/25/2017-8-25-learn-tensorflow-shared-variables/ Tensorflow does ...

  5. Hdu 6598 Harmonious Army 最小割

    N个人 每个人可以是战士/法师  M个组合 每个组合两个人 同是战士+a 同是法师+c 否则+b 对于每一个u,v,a,b,c 建(S,u,a) (u,v,a+c-2*b) (v,T,c) (S,v, ...

  6. Python MySQL 数据库连接不同方式

    PyMySQL 驱动连接 什么是 PyMySQL?PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb. PyMySQL 遵循 P ...

  7. 在Visual Studio Code 运行 webpack ./src/main.js --output-filename ./dist/bundle.js --output-path . --mode development 提示 Module no t found:Error:Can't resolve' 'jquery' 是因为vs code还没安装jquery

    在Visual Studio Code 运行 webpack ./src/main.js --output-filename ./dist/bundle.js --output-path . --mo ...

  8. adreno的tbdr

    看完apple的(&&powervr) 再来撸高通的.. FlexRender 能自己选三种模式 Direct Binning 这个只是分块 HWVizBinning 这个估计就是tb ...

  9. Qt 模型/视图结构

    MVC是一种与用户界面相关的设计模式.通过使用此模型,可以有效地分离数据和用户界面.MVC设计模式包含三要素:表示数据的模型(Model).表示用户界面的视图(View)和定义了用户在界面上的操作控制 ...

  10. 题解 【Uva】硬币问题

    [Uva]硬币问题 Description 有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多.给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值 ...