clone类

JAVA提供了一个Cloneable接口,但是这个接口为一个空接口,它没有定义任何的方法。一个没有定义任何方法的接口能够做什么呢?从官方文档上可以看出,这个Cloneable接口是用来与Object类的clone方法结合使用。当一个类实现了Cloneable这个接口时,那么他就可以使用这个clone接口,否则它将抛出一个异常CloneNotSupportedException。这是理想的情况,但是,实际情况却不是这个样子,就是因为Cloneable接口为空。

我们在看一下这个Object的clone方法是如何定义的,首先它是一个protected方法,那么外部的对象就无法直接使用这个接口,如果需要使用clone方法,那么应该继承这个Object类,并覆盖clone方法,指定其访问修饰符为public,下面我们演示一段程序,定义一个支持clone方法的类WebSite。

  1. class WebSite implements Cloneable{  

  2. private String mDomainName;  

  3. private String mName;  

  4. private String mEmail;  

  5. privateint mAge;  

  6. privateint mClick;  

  7. public WebSite(){  

  8.        mDomainName = "www.jiesoon.com";  

  9.        mName = "jiesoon";  

  10.        mEmail = "jiesoon@jiesoon.com";  

  11.        mAge = 3;  

  12.        mClick = 3000;  

  13.    }  

  14. public WebSite(String domainName, String name, String email,  

  15. int age, int click){  

  16.        mDomainName = new String(domainName);  

  17.        mName = new String(name);  

  18.        mEmail = new String(email);  

  19.        mAge = age;  

  20.        mClick = click;  

  21.    }  

  22. publicvoid setDomainName(String domainName){  

  23.        mDomainName = domainName;  

  24.    }  

  25. publicvoid setAge(int age){  

  26.        mAge = age;  

  27.    }  

  28. publicvoid print(){  

  29.        System.out.println("Domain name:" + mDomainName);  

  30.    }  

  31. public Object clone(){  

  32. returnnew WebSite(mDomainName, mName,  

  33.                mEmail, mAge, mClick);  

  34.    }  

  35. }  

在这个WebSite类中,我们定义了两个构造函数,两个设置函数,一个clone函数和一个打印函数,而这个类同时实现了Cloneable接口,需要注意的是:Cloneable接口不包含任何方法,clone方法是覆盖了Object类的方法。在这个类的定义中,我们定义了一个缺省构造函数和一个含有5个参数的构造函数,这个构造函数为创建当前对象copy的方法。完成这个WebSite类的定义之后,我们就可以实现通过clone接口来创建一个WebSite对象的copy。

  1. publicclass JSCloneable {  

  2. publicstaticvoid main(String[] args) {  

  3.        WebSite jiesoon = new WebSite();  

  4.        WebSite java = (WebSite)jiesoon.clone();  

  5.        java.setDomainName("java.jiesoon.com");  

  6.        jiesoon.print();  

  7.        java.print();  

  8.    }  

  9. }  

在上述的测试代码中,我们使用WebSite的缺省构造函数创建了jiesoon对象,之后我使用jiesoon对象的clone方法构造了一个新的WebSite对象java,在clone函数中,我们采用将当前WebSite对象中的5个参数构造一个WebSite对象的方法,而不是单独地指向这个jiesoon对象。这样就意味着两个WebSite对象现在是完全独立的,如果我们在clone方法中采用赋值的方式:

  1. public Object clone(){  

  2. returnthis;  

  3. }  

那么,jiesoon和java为两个完全相同的对象,而不是执行的clone操作。

在文章的前面,我们介绍了Cloneable接口为一个空接口,所以我们在定义这个类WebSite的时候,其实可以省略从Cloneable实现(强烈建议不要省略这个Cloneable接口),这样做完全是合乎语法的。

  1. class WebSite/* implements Cloneable*/{  

  2. //定义函数与成员变量

  3. }  

clone类的特性

在上述的代码示例中,我们实现了自己的Cloneable方法和覆盖了clone接口,通过使用clone方法所构建的WebSite对象(java)与原来的WebSite对象(jiesoon)有什么区别和联系呢?

两个不同的对象

创建完成jiesoon和java这两个WebSite对象之后,我们使用!=操作符来比较两个对象是否为同一个对象,如下的代码:

  1. publicstaticvoid main(String[] args) {  

  2.    WebSite jiesoon = new WebSite();  

  3.    WebSite java = (WebSite)jiesoon.clone();  

  4.    java.setDomainName("java.jiesoon.com");  

  5.    jiesoon.print();  

  6.    java.print();  

  7. if(jiesoon != java){  

  8.        System.out.println("jiesoon != java");  

  9.    }  

  10. }  

上述的输出为:jiesoon != java,表明clone出来的WebSite对象是一个崭新的WebSite对象。

隶属于同一个类

我们使用下面的代码将这两个对象的类名称打印出来:

  1. publicstaticvoid main(String[] args) {  

  2.    WebSite jiesoon = new WebSite();  

  3.    WebSite java = (WebSite)jiesoon.clone();  

  4.    java.setDomainName("java.jiesoon.com");  

  5.    System.out.println("jiesoon.class:" + jiesoon.getClass());  

  6.    System.out.println("java.class:" + java.getClass());  

  7. }  

这两个输出结果为:

jiesoon.class:class com.jiesoon.WebSite

java.class:class com.jiesoon.WebSite

也就是说,它们都隶属于WebSite类。

成员内容

我们在这个WebSite类中对于成员内容的输出只包含了一项内容:域名信息。但我们在clone中对所有的成员都进行了复制,它们在成员变量的内容上是完全一致的,下面的代码只输出了域名:

  1. publicstaticvoid main(String[] args) {  

  2.    WebSite jiesoon = new WebSite();  

  3.    WebSite java = (WebSite)jiesoon.clone();  

  4.    jiesoon.print();  

  5.    java.print();  

  6. }  

综上所述,我们可以得出这样的结论:clone方法是实现对象复制的关键,Cloneable是一个空接口;clone出来的对象是一个全新的对象,它与原来的对象没有关系;clone出来的对象其内容与原来对象的内容应保持一致。

完整代码

  1. package com.jiesoon;  

  2. class WebSite implements Cloneable{  

  3. private String mDomainName;  

  4. private String mName;  

  5. private String mEmail;  

  6. privateint mAge;  

  7. privateint mClick;  

  8. public WebSite(){  

  9.        mDomainName = "www.jiesoon.com";  

  10.        mName = "jiesoon";  

  11.        mEmail = "jiesoon@jiesoon.com";  

  12.        mAge = 3;  

  13.        mClick = 3000;  

  14.    }  

  15. public WebSite(String domainName, String name, String email,  

  16. int age, int click){  

  17.        mDomainName = new String(domainName);  

  18.        mName = new String(name);  

  19.        mEmail = new String(email);  

  20.        mAge = age;  

  21.        mClick = click;  

  22.    }  

  23. publicvoid setDomainName(String domainName){  

  24.        mDomainName = domainName;  

  25.    }  

  26. publicvoid setAge(int age){  

  27.        mAge = age;  

  28.    }  

  29. publicvoid print(){  

  30.        System.out.println("Domain name:" + mDomainName);  

  31.    }  

  32. public Object clone(){  

  33. returnnew WebSite(mDomainName, mName,  

  34.                mEmail, mAge, mClick);  

  35.    }  

  36. }  

  37. class Page implements Cloneable{  

  38. public Object clone(){  

  39. returnnew Page();  

  40.    }  

  41. }  

  42. publicclass JSCloneable {  

  43. /**

  44.     * @param args

  45.     */

  46. publicstaticvoid main(String[] args) {  

  47.        WebSite jiesoon = new WebSite();  

  48.        WebSite java = (WebSite)jiesoon.clone();  

  49.        jiesoon.print();  

  50.        java.print();  

  51. if(jiesoon != java){  

  52.            System.out.println("jiesoon != java");  

  53.        }  

  54.        System.out.println("jiesoon.class:" + jiesoon.getClass());  

  55.        System.out.println("java.class:" + java.getClass());  

  56.    }  

  57. }