public class Employee implements Cloneable{
private float salary;
private String name;
private Date hireDay;
/**
* 使用场景:比如在方法中传递一个对象,这时候你需要使用到这个对象进行操作,你需要做更新对象的相关数据,
* 但是又不想改变这个对象,因为更新对象的操作应用只是在方法里面,这时候可以克隆一份对象进行操作即可
*
* 使用场景:在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,
* 并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。在Java语言中,
* 用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段
*
* 相关网页说明:
* 1、http://blog.youkuaiyun.com/shootyou/article/details/3945221
* 2、http://blog.youkuaiyun.com/it_man/article/details/1404550
* 3、http://blog.youkuaiyun.com/naivesoft/article/details/6774550 【java克隆中String的特殊性】
*
* 影子克隆和深度克隆的区别:
* 调用Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,
* 但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。
*
* 注:克隆的话是八大基本类型加上String类型,因为String类型是不可改变的,每次赋值都会分配新的一块内存
*/
/**
*
* @param args
* @throws CloneNotSupportedException 如果不实现Cloneable接口,那么一定会抛出这个异常
*/
public static void main(String[] args) throws CloneNotSupportedException {
Employee e=new Employee(3000.0f,"xw",new Date());
/* 浅复制(Shallow Clone)
* Object在对某个对象实施Clone时对其是一无所知的,它仅仅是简单地执行域对域的copy
* 它里面有一个域hireDay不是基本型别的变量,而是一个reference变量,经过Clone之后就会产生一个新的Date型别的
* reference,它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息
*/
Employee e1=(Employee)e.clone();
System.out.println(e1.hashCode()+":"+e.hashCode());//两个对象不一样了,hashcode不一样
e1.salary=200;
e1.name="hj";
e1.hireDay.setDate(9);
System.out.println(e.salary+"#"+e1.salary);//3000.0#200.0
System.out.println(e.name+"#"+e1.name); //xw#hj ??这里应该也是引用的改变,不知道为什么原来的name没改变
System.out.println(e.hireDay.getDate()+"#"+e1.hireDay.getDate());//9#9
//因为是浅复制,所以引用变量会共享信息
//但是当重写了clone方法之后得到的值是7#9
}
public Employee(float salary,String name,Date hireDay){
this.salary=salary;
this.name=name;
this.hireDay=hireDay;
}
@Override
/*
* 为了不让引用变量与原来被克隆的对象不共享同一份数据,需要进行深复制(deep Clone)
* 重新定义Clone方法,对那些非基本型别的域进行特殊的处理
*/
protected Object clone() throws CloneNotSupportedException {
Employee clone=(Employee)super.clone();//对e对象的一份克隆,生成一份全新的对象
clone.hireDay=(Date)hireDay.clone();//对成员变量的一份克隆,避免与被克隆的对象共用同一份引用
//这时候得到的hireDay是还未改变过的hireDay,还停留在创建对象为构造方法赋值的时候的变量值
return clone;
}
}
/**
输出结果:
14576877:12677476
3000.0#200.0
xw#hj
24#9
*/