JAVA对象克隆可能会出现的问题
首先,区分一下拷贝和克隆:
拷贝:当拷贝一个变量时,原始变量与拷贝变量引用的是同一个对象。当改变一个变量所引用的对象,则会对另一个变量造成影响。
克隆:当克隆一个对象时,是重新的创建了和该对象内容相同的对象。
clone方法是Object类受保护(preteced)方法,用户编写的代码不能直接调用。只有相同的类才能克隆其本身。
问题:
如果待克隆的对象中的所有数据域都是数值或基本类型,这样的克隆没有问题。
但是,如果在对象中包含了子对象的引用,拷贝的结果就会使得两个域引用同一个子对象,此时,原始对象和克隆对象将共享这一部分信息。
这样,当克隆对象改变这部分时,就会造成原始对象中数据的改变。
默认的克隆操作都是浅拷贝,它并没有克隆包含在对象中的内部对象。
进行浅拷贝会发生什么?
如果原始对象与浅克隆对象共享的子对象是不可变的,这样就不会产生问题。
但是,更多的情况是子对象是可变的。这样,就必须重写clone方法,以实现克隆子对象的深度拷贝。
对于待克隆的对象,需要作出一些判断:
(1)默认的克隆方法是否能够满足要求;
(2)默认的克隆方法是能够通过调用可变子对象的clone方法进行修补;
(3)是否不应该使用clone。
如果选1或2,类必须:
实现Cloneable接口,并使用public访问修饰符重新定义clone方法。
下面举例说明克隆机制:
import java.util.Date;
import java.util.GregorianCalendar;
public class TestClone {
public static void main(String[] args) {
try {
/**原始对象**/
Employee origin = new Employee("Tom", 10000);
origin.setHireDay(2014, 10, 10);
/**克隆Employee对象**/
Employee copy = origin.clone();
copy.raiseSalary(10);
copy.setHireDay(2015, 11, 11);
System.err.println(origin); /**Tom,10000.0,Mon Nov 10 00:00:00 CST 2014**/
System.err.println(copy); /**Tom,11000.0,Fri Dec 11 00:00:00 CST 2015**/
/**
* 可以看出数据域属于数值或基本类型时,克隆不会对其值造成影响,
* 而类似Date这样的对象在进行克隆时就需要特别注意,必须进行深度克隆,将子对象也进行克隆
*/
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class Employee implements Cloneable {
private String name;
private double salary;
private Date hireDay;
public Employee(String n, double s) {
this.name = n;
this.salary = s;
this.hireDay = new Date();
}
public Employee clone() throws CloneNotSupportedException {
/** 调用Object的clone方法 **/
Employee cloned = (Employee) super.clone();
/** 克隆可变的域对象 对可变的子对象进行克隆 **/
cloned.hireDay = (Date) hireDay.clone();
/**如果注释掉上面hireDay的克隆,最终将会得到如下结果,原始对象和克隆对象都指向同一个对象**/
/**Tom,10000.0,Fri Dec 11 00:00:00 CST 2015**/
/**Tom,11000.0,Fri Dec 11 00:00:00 CST 2015**/
return cloned;
}
public void setHireDay(int year, int month, int day) {
Date newHireday = new GregorianCalendar(year, month, day).getTime();
hireDay.setTime(newHireday.getTime());
}
public void raiseSalary(double byPrecent){
double raise = salary * byPrecent / 100;
salary += raise;
}
/**重写Object类的toString方法**/
public String toString(){
return new StringBuffer().append(name).append(",").append(salary).append(",")
.append(hireDay).toString();
}
}
JAVA对象克隆可能会出现的问题的更多相关文章
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
- (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- java对象克隆复制
原文链接:https://blog.csdn.net/ztchun/article/details/79110096 自己先简单描述总结一下:当想要将一个对象中已有的值直接给另外一个对象的时候,其实并 ...
- java对象克隆以及深拷贝和浅拷贝
1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...
- JAVA对象克隆
1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法. 2> 在派生类中覆盖基类的clone(),并声明为public.3> 在派生类的clone()方法中, ...
- Java提高篇——对象克隆(复制)
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
- Java对象和集合的拷贝/克隆/复制
昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作.但是他对新的Bean操作后,会影响旧的Bean的值.当听到这个问题的时候,我第一反应就是他的拷贝方法 ...
随机推荐
- java1.8十大新特性详解
"Java is still not dead-and people are starting to figure that out." 本教程将用带注释的简单代码来描述新特性,你 ...
- Oracle中备份用户对象的两种方法
方法1: 执行步骤: exp userid=用户名/密码@数据库名 file=c:\emp.dmp 使用当前用户导出 exp userid=sys/sys@数据库名 file=c:\emp.dmp o ...
- python 循环和file操作实现用户密码输错三次将用户锁定
一.需求编写登录接口1.输入用户名密码2.认证成功后显示欢迎信息3.输错三次后锁定 二.简单思路登录,三次密码输入错误锁定用户1.用户信息文件:存放用户名和密码2.黑名单文件:将输入三次错误的用户加入 ...
- Android开发过程中在sh,py,mk文件中添加log信息的方法
Android开发过程中在sh,py,mk文件中添加log信息的方法 在sh文件中: echo "this is a log info" + $info 在py文件中: print ...
- 安卓高级8 SurfaceView (1)
文章转载:http://www.cnblogs.com/xuling/archive/2011/06/06/android.html 首先我们先来看下官方API对SurfaceView的介绍 Surf ...
- 到底什么是集群&分布式
对于楼主这样工作一年的菜鸟,偶尔会看到一些文章标题带有"分布式""集群"关键字,然后就懵逼了.最近对这些概念进行了一定的了解,整理了一下思路,在这里分享给各位猿 ...
- [BBS]搭建开源论坛之JForum安装使用札记
本文作者:sushengmiyan 本文地址:http://blog.csdn.net/sushengmiyan/article/details/47761303 目录 目录 BBS搭建开源论坛之JF ...
- EBS业务学习之应付INVOICE类型
INVOICE类型 类 型 描 述 标准INVOICE 是指由于采购货物或接受劳务,从供应商处取得的INVOICE (标准INVOICE,既可以和订单匹配,也可以不匹配) ...
- FORM内置系统变量
常用 和输入焦点有关: SYSTEM.CURSOR_ITEM:返回系统当前正在操作的项名. SYSTEM.CURSOR_RECORD:返回系统当前正在操作的记录行号. SYSTEM.CURSOR_BL ...
- openJdk和sun Jdk区别和安装
openJdk和sun jdk的区别 使用过LINUX的人都应该知道,在大多数LINUX发行版本里,内置或者通过软件源安装JDK的话,都是安装的OpenJDK, 那么到底什么是OpenJDK,它与SU ...