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

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

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

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. 【已解决】IIS搭建 asp.net core 项目后 其他电脑访问不到资源文件

    IIS搭建asp.net core 项目后,访问不到里面的资源文件(图片等),解决方法如下: 1.检查asp.net core发布文件中的资源文件是不是都放到了wwwroot名称的目录中. 2.检查a ...

  2. Protobuf3语法详解

    定义一个消息类型 先来看一个非常简单的例子.假设你想定义一个"搜索请求"的消息格式,每一个请求含有一个查询字符串.你感兴趣的查询结果所在的页数,以及每一页多少条查询结果.可以采用如 ...

  3. hiredis异步接口封装并导出到Lua

    hiredis异步接口封装并导出到Lua(金庆的专栏 2017.1)hiredis 不支持 Windows, Windows 下使用 wasppdotorg / hiredis-for-windows ...

  4. mysql和postgresql转义字符探究

    总结 mysql依靠反斜杠\转义, postgresql 依靠单引号转义 mysql 客户端 mysql> create table usr (name varchar(), age integ ...

  5. iOS学习笔记--数据存储

    iOS应用数据存储的常用方式 XML属性列表(plist)归档 Preference(偏好设置) NSKeyedArchiver归档(NSCoding) SQLite3 Core Data 1. XM ...

  6. Android EditText在ScrollView中被输入法遮挡

    千言万语不如一张图来的实在,问题如下GIF图所示[输入框被输入法挡住了]: 为了不让底部的按钮随着输入法一起起来,我把windowSoftInputMode设置为adjustPan. <acti ...

  7. android 网络工具 之Android-Volley的demo

    1.今天详细的研究了Volley的使用,下面来给大家介绍一下: Android Volley 是Google开发的一个网络lib,可以让你更加简单并且快速的访问网络数据.Volley库的网络请求都是异 ...

  8. JAVA面向对象-----内部类的概述

    JAVA面向对象-–内部类的概述s 将类定义在另一个类的内部则成为内部类.其实就是类定义的位置发生了变化. 在一个类中,定义在类中的叫成员变量,定义在函数中的叫成员函数,那么根据类定义的位置也可以分为 ...

  9. ActiveMQ安装配置及实例

    本文可作为吴水成老师,dubbo课程第21节的学习笔记. ActiveMQ的介绍及功能 参考百度 ActiveMQ的下载 https://activemq.apache.org/activemq-51 ...

  10. VS2008界面语言设置

    在卸载某个软件的时候,不知道什么原因导致vs2008的界面变成中文的了,但是菜单还是英文的,很不美观. 几经查找,最后可以在如下的地方设置界面语言 Tools -> Options 如果设置成 ...