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的值.当听到这个问题的时候,我第一反应就是他的拷贝方法 ...
随机推荐
- node之fs模块
前言 fs是filesystem的缩写,该模块提供本地文件的读写能力,基本上是POSIX文件操作命令的简单包装.但是,这个模块几乎对所有操作提供异步和同步两种操作方式,供开发者选择. 一.文件读取 文 ...
- Nginx配置二级目录/路径 映射不同的反向代理和规避IP+端口访问
当配置Nginx来映射不同的服务器 可以通过二级路径来反向代理 来解决一个外网端口实现多个服务访问. 配置如下: server { listen ; server_name demo.domai ...
- WPF ListBox 获取listBoxItem
1.已知item的DataContext,获取ListBoxItem 1)ItemContainerGenerator.ContainerFromItem var selectedItem = Doc ...
- iOS支付宝,微信,银联支付集成封装(上)
一.集成支付宝支付 支付宝集成官方教程https://docs.open.alipay.com/204/105295/ 支付宝集成官方demo https://docs.open.alipay.com ...
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap,第 1 部分: kprobe
kprobe 的原理.编程接口.局限性和使用注意事项 本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprobe以及促使开发该工具的先驱DTr ...
- 理解性能的奥秘——应用程序中慢,SSMS中快(2)——SQL Server如何编译存储过程
本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 接上文:理解性能的奥秘--应用程序中慢,SSMS中快(1)--简介 本文介绍SQL Server如何编译存储过程并使用计划缓存 ...
- DoesNotExist at /admin/
DoesNotExist at /admin/ User has no account. Request Method: GET Request URL: http://127.0.0.1:8000/ ...
- The packages can be overrided by Java Endorsed Standards
Endorsed Standards APIs The Endorsed Standards for Java SE constitute all classes and interfaces ...
- Linux 高性能服务器编程——Linux服务器程序规范
问题聚焦: 除了网络通信外,服务器程序通常还必须考虑许多其他细节问题,这些细节问题涉及面逛且零碎,而且基本上是模板式的,所以称之为服务器程序规范. 工欲善其事,必先利其器,这篇主要来探 ...
- 小米手机无法连接eclipse调试解决方案
今天在做百度地图开发的时候,用genymotion调试一直出错,重启几次都是错的,后来我换成真机发现好了.当然我的小米3连接eclipse一直连不进去,折腾死我了,在网上查了很多资料,发现很多都不能用 ...