A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© Tking 中级黑马   /  2014-4-11 07:09  /  1036 人查看  /  1 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

java克隆机制
克隆(clone):创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。
通俗易懂的说法:将一个已经存在的实例对象,复制成多个实例,而且每个实例对象直接并没有联系,不会改一处,多处改变。也相当于Copy一样。
而克隆机制也分为深克隆(Shallow clone)与浅克隆(Deep clone),下面通过几个实例来演示。
首先:要克隆的类必须实现Cloneable,这是个许可证,么实现该接口,并重写其方法的类不能实现克隆。
1、定义一个类允许克隆。
  1. class Aa implements Cloneable//克隆的前提
  2. {
  3.   Int i=1;;
  4.   @override//必须实现的方法
  5.         protected Object clone() throws CloneNotSupportedException {
  6.                 return super.clone();
  7.           }
  8. }
  9. public class Demo05 {

  10.         Public static void main(String[] args) throws CloneNotSupportedException {
  11.                 Aa a=new Aa();
  12.                 Aa b=(Aa)a.clone();
  13.   Aa c=a;
  14.                 System.out.println(a.i);
  15.                 System.out.println(b.i);
  16.                 System.out.println(c.i);       
  17.         }
  18. }
  19. //运行结果:
  20.   1
  21.   1
  22.   1
复制代码
这样的结果很可能产生两种误会,对有没有过基础的会觉得,把a赋给了b和c。
对了解java指针机制的就会说,b和a都指向了a。两者都只对了一半。
下面增加两行代码就明白了;
  1.   Aa a=new Aa();
  2.                 Aa b=(Aa)a.clone();
  3.                 Aa c=a;
  4.                 b.i=10;
  5.                 c.i=5;
  6.                 System.out.println(a.i);
  7.                 System.out.println(b.i);
  8.                 System.out.println(c.i);
  9. //运行结果:
  10.   5
  11.   10
  12.   5
复制代码
显而易见,c变量指向了a,而b变量却是将a变量完全复制过来。很多时候我们都想得到某个对象的副本,暂时修改其属性又不能令对象的属性改变,很矛盾,这是这里可以用到clone关键字,但是这种克隆只能算得上浅度克隆(Shallow Clone)。
什么是深克隆?什么事浅克隆?
实例:在Aa这类中多了一个其他类的对象
  1. class Aa implements Cloneable
  2. {
  3.         int i=1;
  4.         B field=new B();
  5.         @Override
  6.         protected Object clone() throws CloneNotSupportedException {
  7.                 return super.clone();
  8.         }
  9. }
  10. class B
  11. {
  12.         int i=1;
  13.         public int getI() {
  14.                 return i;
  15.         }
  16.         public void setI(int i) {
  17.                 this.i = i;
  18.         }
  19. }
  20. //然后主程序依旧按照常规克隆;
  21.   Aa a=new Aa();
  22.                 Aa b=(Aa)a.clone();
  23.                 b.field.setI(10);
  24.                 System.out.println(a.field.getI());
  25.                 System.out.println(b.field.geitI());
  26. //运行结果:
  27.   10
  28.   10
复制代码
结果出乎意料,咋么又变成指针机制了?
要知道这些,先要了解Object在调用clone方法的时候都做了些什么。
Object在对某个实施Clone时对其对象一无所知,仅仅只是简单的做了一个Copy的动作,这就是浅克隆。但是在Aa类中却有一个引用型变量,当克隆时候,就把该对象的地址给克隆了,并没有克隆出实力对象。也可以验证下。
  1.   System.out.println(a);
  2.                 System.out.println(b);
  3.                 System.out.println(a.field);
  4.           System.out.println(b.field);
  5. //运行结果:
  6.   Aa@7800e9
  7.   Aa@83dae1
  8.   B@971d55
  9.   B@971d55
复制代码
结果说明,ab不是同一个对象,但是a对象的成员field与b对象的成员field,却是同一个对象,如图:

从图上可以看出,基本类型被克隆了,但是引用类型变量,却只克隆了地址,这种克隆也称作浅克隆(Shallow Clone)
怎么才能做到深度度克隆呢?
其实很简单,只需要重新定义Clone方法,对B类做特殊处理(Deep Clone)深度克隆
  1. class Aa implements Cloneable
  2. {
  3.         int i=1;
  4.         B field=new B();
  5.         @Override
  6.         protected Object clone() throws CloneNotSupportedException {
  7.                 Aa temp=(Aa)super.clone();//先克隆主体
  8.                 temp.field=(B)field.clone();//再克隆引用
  9.                 return temp;
  10.         }
  11. }
  12. class B implements Cloneable//这个类也要实现克隆标记
  13. {
  14.         int i=1;
  15.         public int getI() {
  16.                 return i;
  17.         }
  18.         public void setI(int i) {
  19.                 this.i = i;
  20.         }
  21.   //还要重写克隆方法
  22.         protected Object clone() throws CloneNotSupportedException {
  23.                
  24.                 return super.clone();
  25.         }
  26. }
  27. //这时候在打印:
  28. public static void main(String[] args) throws CloneNotSupportedException {
  29.                 Aa a=new Aa();
  30.                 Aa b=(Aa)a.clone();
  31.                 b.field.setI(100);
  32.                 b.i=10;
  33.                 System.out.println(a.i);
  34.                 System.out.println(b.i);
  35.                 System.out.println(a.field.getI());
  36.                 System.out.println(b.field.getI());
  37.         }
  38. //运行结果:
  39.   1
  40.   10
  41.   1
  42.   100
复制代码
现在的就够就是这样的:

这样就可以达到预想的效果,两个实例直接没有关系了。
总结:
Clone机制:存在两种方式。
1Shallow Clone;这种clone只对基本数据类型有效,对对象内的引用变量无效。
2Deep Clone;对对象所有成员都有效,前提是这些成员都实现了Cloneable接口
3、使用Clone将会抛出异常。
4、两种方式按自己需求而用,



评分

参与人数 1黑马币 +1 收起 理由
枫儿 + 1 赞一个!

查看全部评分

1 个回复

倒序浏览
看帖,要回帖呀,不回帖,写着好没动力:Q
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马