首先,区分一下拷贝和克隆:

拷贝:当拷贝一个变量时,原始变量与拷贝变量引用的是同一个对象。当改变一个变量所引用的对象,则会对另一个变量造成影响。

克隆:当克隆一个对象时,是重新的创建了和该对象内容相同的对象。

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对象克隆可能会出现的问题的更多相关文章

  1. Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...

  2. (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...

  3. Java对象克隆详解

    原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...

  4. java对象克隆复制

    原文链接:https://blog.csdn.net/ztchun/article/details/79110096 自己先简单描述总结一下:当想要将一个对象中已有的值直接给另外一个对象的时候,其实并 ...

  5. java对象克隆以及深拷贝和浅拷贝

    1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...

  6. JAVA对象克隆

    1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法. 2> 在派生类中覆盖基类的clone(),并声明为public.3> 在派生类的clone()方法中, ...

  7. Java提高篇——对象克隆(复制)

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

  8. Java对象的克隆和深浅问题

    Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...

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

    昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作.但是他对新的Bean操作后,会影响旧的Bean的值.当听到这个问题的时候,我第一反应就是他的拷贝方法 ...

随机推荐

  1. 前端开发利器VSCode

    最近找到一款非常好用的开发利器,VSCode.一直认为微软做的东西都很一般,这个软件让我刮目相看了. 之前使用webstorm卡的不行,换了这个非常好用. 用着还不错,这里记录下一些使用的心得. VS ...

  2. 编程英语之KNN算法

    School of Computer Science The University of Adelaide   Artificial Intelligence Assignment 2   Semes ...

  3. redis在java客户端的操作

    redis高性能,速度快,效率高的特点,用来做缓存服务器是很不错的选择.(和memcache相似)redis在客户端的操作步骤: 1.redis单机版操作 1.1通过Jedis对象操作 (1)将安装r ...

  4. UI相关

    前端 UI 框架 https://github.com/twbs/bootstrap https://github.com/google/material-design-lite https://gi ...

  5. ABP文档笔记 - 事件BUS

    文档: ABP框架 - 领域事件(EventBus) EventBus & Domain Events ABP源码分析二十五:EventBus EventBus(事件总线) EventBus是 ...

  6. eclipse中启动tomcat,localhost:8080无法访问

    问题 eclipse中启动tomcat,项目可以正常运行,但是localhost:8080无法访问. 关闭eclipse中的Tomact,直接从tomcat/bin 下的startup.bat启动,l ...

  7. python笔记六(函数的参数、返回值)

    一 调用函数 在写函数之前,我们先尝试调用现有的函数 >>> abs(-9) 9 除此之外,还有我们之前使用的len()等.可以用于数据类型转换的 int() float() str ...

  8. UltraISO安装centos7系统

    1. 使用最新版UltraISO将ISO镜像刻录到U盘一定要是最新版,试用版都可以,按下图操作: 2. U盘启动电脑进入安装界面正常情况下你应该会看到下面的这个界面: 选择第一项,然后按TAB键(在评 ...

  9. 剑指Offer——知识点储备--Linux基本命令+Makefile

    剑指Offer--知识点储备–Linux基本命令 1.linux下查看进程占用cpu的情况(top): 格式 top [-] [d delay] [q] [c] [S] [s] [i] [n] 主要参 ...

  10. Linux 环境下一些常用的命令(二)

    11. chown命令 "chown"命令就是改变文件拥有者和所在用户组.每个文件都属于一个用户组和一个用户.在你的目录下,使用"ls -l",你就会看到像这样 ...