Java Clone机制

(1) Java对象赋值

Java代码 
  1. Employee e1=new Employee("李"); //Employee是一个自定义类    
  2. Employee e2=e1; //赋值对象    
  3. e2.setName("王");//改变对象e2的名字    
  4. System.out.println(e1.getName()); //打印e1的结果: 王    

      这就是Java的对象赋值,改变e2的内容竟然会影响e1的内容。原因很简单,就是e1和e2这两个对象引用都指向了堆中同一个Employee类对象的内容。也就是说: Java的对象赋值的是引用(相当于C的指针)。如何让e1,e2成为内容相同的两个完全不同的对象呢,这就需要用到Java的对象克隆机制(将e2复制成e1的一个独立副本)。

 

 

(2) Java对clone的支持

       Java的万类之祖Object中有一个clone()方法:   

Java代码 
  1. protected native Object clone() throws CloneNotSupportedException  

       这个方法是protected的,显然是为了让子类能够使用(但事实上子类的使用是有要求的,在后面会提到)。而且这个方法又是native的,也就是说这个方法必然做了一些与平台相关的底层工作。但很多人会提这样的问题:既然Java中的所有类都是继承Object的(不管是库类还是自定义的类),那么所有类都可以调用clone()方法了,这样的protected和public简直就没有区别了吗?事实并非如此:下面的代码就会报错: 

Java代码 
  1. //错误代码    
  2. public class cloneTest{    
  3.         public static void main(String[] args) throws CloneNotSupportedException{    
  4.               Employee e1=new Employee(); //Employee是自定义类,也是Object的子类    
  5.          Employee e2=(Employee)e1.clone(); //Error:CloneNotSupportedException    
  6.             
  7.    
  8.   
  9. class Employee{} //自定义类Employee   

        实际上:这并不是protected的作用范围的问题,而是Object的clone()方法在调用的时候必须实现一个重要的接口——Cloneable接口。这种接口我们叫作标记接口(tagging interface) 。这种标记接口没有任何方法,唯一的作用就是作为一个标志,用来告诉JVM一个类是否具有某个特定的功能。说白了,就是实现Cloneable接口的类才是JVM认为具备拷贝能力的类。(上面的Employee类并没有实现Cloneable接口,所有无法clone)

         如此一来,我们只要定义一个具有 Clone 功能的类就可以了:
          1. 在类的声明中加入“ implements Cloneable ”,标志该类有克隆功能;
          2. 重载类 Object 的 clone() 方法,在该方法中调用 super.clone() :

Java代码 
  1. class Employee implements Cloneable{    
  2.             public Object clone() throws CloneNotSupportedException{//重载clone()方法    
  3.               Employee cloned=(Employee)super.clone();    
  4.                      return cloned;    
  5.                
  6.  

 

 

3) 深Clone和浅Clone

       拷贝副本的问题并没有完全解决。clone技术并不是那么简单的。Object中的clone()方法是对具体类对象的各个域进行对应的赋值。如果具体类对象中还有子对象,这个问题就复杂了。

Java代码 
  1. // 具备浅克隆的Employee类   
  2. class Employee implements Cloneable{   
  3.        public String name=""    
  4.        public Date hireDay=null;   
  5.   
  6.        public Object clone(){   
  7.             Employee cloned=(Employee)super.clone();   
  8.             return cloned;   
  9.       }   
  10. }   
  11.   
  12. Employee orignal=new Employee();   
  13. Employee copy=orignal.copy();  

       对于上面的代码,克隆以后orignal与copy中的hireDay指向的是同样的存储位置。也就是说当我们调用copy.hireDay.setTime()方法后,orignal中的hireDay也会发生改变。但String类(由于常量池的存储方式)和基本数据类型变量时不会改变的。这种对子对象克隆无效的方式我们叫做浅克隆 。

       很多情况下,我们需要将对象中的所有域(包括子对象)都进行真正的克隆。要做到这种深克隆,我们必须在重载clone()方法时克隆子对象:

Java代码 
  1. //具备深度克隆功能的Employee类   
  2. class Employee implement Cloneable{   
  3.          public String name="";   
  4.          private Date hireDay=null;   
  5.   
  6.         public Object clone(){   
  7.                 Employee cloned=(Employee)super.clone();  //浅克隆   
  8.            cloned.hireDay=(Date)hireDay.clone(); //克隆子对象   
  9.            return cloned;   
  10.         }   
  11.  

        上面的代码很好理解,就是将克隆体cloned中的hireDay指向新的子对象副本。而不是原来的子对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值