java克隆机制 克隆(clone):创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。 通俗易懂的说法:将一个已经存在的实例对象,复制成多个实例,而且每个实例对象直接并没有联系,不会改一处,多处改变。也相当于Copy一样。 而克隆机制也分为深克隆(Shallow clone)与浅克隆(Deep clone),下面通过几个实例来演示。 首先:要克隆的类必须实现Cloneable,这是个许可证,么实现该接口,并重写其方法的类不能实现克隆。 1、定义一个类允许克隆。 - class Aa implements Cloneable//克隆的前提
- {
- Int i=1;;
- @override//必须实现的方法
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- }
- public class Demo05 {
- Public static void main(String[] args) throws CloneNotSupportedException {
- Aa a=new Aa();
- Aa b=(Aa)a.clone();
- Aa c=a;
- System.out.println(a.i);
- System.out.println(b.i);
- System.out.println(c.i);
- }
- }
- //运行结果:
- 1
- 1
- 1
复制代码这样的结果很可能产生两种误会,对有没有过基础的会觉得,把a赋给了b和c。 对了解java指针机制的就会说,b和a都指向了a。两者都只对了一半。 下面增加两行代码就明白了; - Aa a=new Aa();
- Aa b=(Aa)a.clone();
- Aa c=a;
- b.i=10;
- c.i=5;
- System.out.println(a.i);
- System.out.println(b.i);
- System.out.println(c.i);
- //运行结果:
- 5
- 10
- 5
复制代码显而易见,c变量指向了a,而b变量却是将a变量完全复制过来。很多时候我们都想得到某个对象的副本,暂时修改其属性又不能令对象的属性改变,很矛盾,这是这里可以用到clone关键字,但是这种克隆只能算得上浅度克隆(Shallow Clone)。 什么是深克隆?什么事浅克隆? 实例:在Aa这类中多了一个其他类的对象 - class Aa implements Cloneable
- {
- int i=1;
- B field=new B();
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- }
- class B
- {
- int i=1;
- public int getI() {
- return i;
- }
- public void setI(int i) {
- this.i = i;
- }
- }
- //然后主程序依旧按照常规克隆;
- Aa a=new Aa();
- Aa b=(Aa)a.clone();
- b.field.setI(10);
- System.out.println(a.field.getI());
- System.out.println(b.field.geitI());
- //运行结果:
- 10
- 10
复制代码结果出乎意料,咋么又变成指针机制了? 要知道这些,先要了解Object在调用clone方法的时候都做了些什么。 Object在对某个实施Clone时对其对象一无所知,仅仅只是简单的做了一个Copy的动作,这就是浅克隆。但是在Aa类中却有一个引用型变量,当克隆时候,就把该对象的地址给克隆了,并没有克隆出实力对象。也可以验证下。 - System.out.println(a);
- System.out.println(b);
- System.out.println(a.field);
- System.out.println(b.field);
- //运行结果:
- Aa@7800e9
- Aa@83dae1
- B@971d55
- B@971d55
复制代码结果说明,a和b不是同一个对象,但是a对象的成员field与b对象的成员field,却是同一个对象,如图: 从图上可以看出,基本类型被克隆了,但是引用类型变量,却只克隆了地址,这种克隆也称作浅克隆(Shallow Clone) 怎么才能做到深度度克隆呢? 其实很简单,只需要重新定义Clone方法,对B类做特殊处理(Deep Clone)深度克隆; - class Aa implements Cloneable
- {
- int i=1;
- B field=new B();
- @Override
- protected Object clone() throws CloneNotSupportedException {
- Aa temp=(Aa)super.clone();//先克隆主体
- temp.field=(B)field.clone();//再克隆引用
- return temp;
- }
- }
- class B implements Cloneable//这个类也要实现克隆标记
- {
- int i=1;
- public int getI() {
- return i;
- }
- public void setI(int i) {
- this.i = i;
- }
- //还要重写克隆方法
- protected Object clone() throws CloneNotSupportedException {
-
- return super.clone();
- }
- }
- //这时候在打印:
- public static void main(String[] args) throws CloneNotSupportedException {
- Aa a=new Aa();
- Aa b=(Aa)a.clone();
- b.field.setI(100);
- b.i=10;
- System.out.println(a.i);
- System.out.println(b.i);
- System.out.println(a.field.getI());
- System.out.println(b.field.getI());
- }
- //运行结果:
- 1
- 10
- 1
- 100
复制代码现在的就够就是这样的: 这样就可以达到预想的效果,两个实例直接没有关系了。 总结: Clone机制:存在两种方式。 1、Shallow Clone;这种clone只对基本数据类型有效,对对象内的引用变量无效。 2、Deep Clone;对对象所有成员都有效,前提是这些成员都实现了Cloneable接口 3、使用Clone将会抛出异常。 4、两种方式按自己需求而用,
|