java.lang.Cloneable解析

java.lang
Interface Cloneable

All Known Subinterfaces:
所有已知的子接口

AclEntry, Attribute, AttributedCharacterIterator, Attributes, CertPathBuilderResult,CertPathParameters, CertPathValidatorResult, CertSelector,
 CertStoreParameters, CharacterIterator, CRLSelector, Descriptor, GSSCredential,
  Name

public interface Cloneable

A class implements the Cloneable interface to indicate to the Object.clone() 
method that it is legal for that method to make a field-for-field copy of 
instances of that class.

Invoking Object's clone method on an instance that does not implement the 
Cloneable interface results in the exception CloneNotSupportedException being 
thrown.

By convention, classes that implement this interface should override Object.clone
 (which is protected) with a public method. See Object.clone() for details on
  overriding this method.

Note that this interface does not contain the clone method. Therefore, it is not
 possible to clone an object merely by virtue of the fact that it implements this 
 interface. Even if the clone method is invoked reflectively, there is no 
 guarantee that it will succeed.

此类实现了Cloneable interface以表明Object.clone() 方法可以以合法的方式对该class的实例进行复制。

如果调用clone method方法的实例没有implements Cloneable接口,那么会抛出CloneNotSupportedException Exception。

按照习惯,implements了Cloneable接口的classes需要重载Object.clone(它是protected)。

注意,这个interface不包含clone method。因此,某个对象实现了它就clone是不可能的。即使反射调用clone method,也不会保证该调用会成功。

Since:
JDK1.0
See Also:
CloneNotSupportedException, Object.clone()


以上直接翻译自java doc,想必已经很清楚了吧。接下来,技改出一个简单的例子,来记录一下。

/**
 * Created by canglangwenyue on 12/5/14.
 */
public class Person implements Cloneable {

    private int id;
    private String name;

    public String getName() {
    return name;
    }

    public int getId() {
    return id;
    }

    public void setId(int id) {
    this.id = id;
    }

        public void setName(String name) {
    this.name = name;
        }

    @Override
    protected Object clone() {

    Person copy = null;

    try {
        copy = (Person) super.clone();
        copy.clone().getClass().getName();

    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    } finally {
        return copy;
    }


        }

        @Override
    public boolean equals(Object obj) {
    return super.equals(obj);
    }

    /**
     * 引用复制的测试
     */

        public static void referenceTest() {
    Person person = new Person();

    person.setId(1);
    person.setName("WenYue");

    Person copy = person;

    if (copy.equals(person))
        System.out.println("引用复制的person和copy是同一个对象");
    else
        System.out.println("引用复制的person和copy不是同一个对象");

    System.out.println(person);
    System.out.println(copy);
    System.out.println(person.getName());
    System.out.println(copy.getName());

        }

    /**
     * 对于Object的clone的测试方法,并检测出clone实现的是浅拷贝
     */
        public static void cloneTest(){
    Person person = new Person();

    person.setId(1);
    person.setName("WenYue");

    Person copy = null;

    copy = (Person) person.clone();

    if (copy.equals(person))
        System.out.println("clone的person和copy是同一个对象");
    else
        System.out.println("clone的person和copy不是同一个对象");

    System.out.println(person);
    System.out.println(copy);
    System.out.println(person.getName());
    System.out.println(copy.getName());

    String result = person.getName()==copy.getName()?"clone是浅拷贝":"clone是深拷贝";
    System.out.println(result);
        }

    public static void main(String[] args) {
    /*测试clone*/
    cloneTest();

    /*测试引用复制*/
    referenceTest();

    }


    }

给出main函数的执行结果:

Alt text

好了,现在来解释一下这段测试代码。

可以看到main函数中执行了两个测试方法,cloneTest()和referenceTest();第一个实现了Cloneable interface后的Object进行clone() method的测试;而之所以添加第二个method的原因是将对象的浅拷贝,即clone(java 中默认对象的拷贝是浅拷贝)。,与引用的复制进行对比,便于大家理解。

1.从这段代码的执行结果中可以清晰地看到,clone实现的copycopy创建了新对象(在内存中的地址不同),而reference的复制,只是把原对象的地址复制给了新对象,所以直行后,person和copy指向了相同的地址空间。

关于clone默认是浅拷贝的解释

2. 首先,由于id是基本数据类型, 那么对它的拷贝没有什么疑议,直接将一个4字节的整数值拷贝过来就行。但是name是String类型的,而且name只是一个引用,指向真正的String对象,之所以说clone默认是浅拷贝的原因就是,在clone时clone方法只是把String对象的引用值拷贝给了新的copy对象的name字段;而并非在内存中重新创建一个String对象,并让copy对象的name字段的引用指向它。证明如下:

 String result = person.getName()==copy.getName()?"clone是浅拷贝":"clone是深拷贝";
首先请大家看着行代码,大概意思是若二者在内存中的地址相同,则返回"clone是浅拷贝",而内存中的地址空间是否相同便可以判断是否是同一个对象。

3.正如前面文档解释的implements了Cloneable接口的classes需要重载Object.clone。

这里挖个坑吧,关于深拷贝的仔细研究,我就在之后来填。