天天看點

java cloneable 接口_JDK源碼閱讀筆記-Cloneable接口

JDK 版本:1.8

代碼位址

1.前言

clone方法能友善的獲得一個對象的拷貝,但其中也有些細節需要注意。

2.實作注意事項

2.1 要調用 clone 方法必須實作 Cloneable 接口

如果類沒有實作 Cloneable 接口,類的執行個體卻調用了 clone 方法,則會抛出CloneNotSupportedException異常。

用反射機制去調用 Objec 類的 clone 方法,可以觀察到這個現象:

Object object = new Object();

Method method = object.getClass().getDeclaredMethod("clone");

method.setAccessible(true);

method.invoke(object);

運作結果:

Caused by: java.lang.CloneNotSupportedException: java.lang.Object

at java.lang.Object.clone(Native Method)

2.2 clone 方法的預設實作是淺拷貝

clone 方法的預設實作是拷貝,即對于類中可變對象沒有進行真正的拷貝,隻是将該可變對象指派給了克隆對象對應的字段。修改目前對象中可變對象也會影響到克隆對象中相應的字段。

舉個例子來說明下:

private static void shallowCopyTest() {

Person ming = new Person("ming", new String[]{"mingMing", "daMing"});

compareCloneObject(ming);

}

private static void compareCloneObject(Person person) {

try {

Person fakePerson = (Person) person.clone();

System.out.println("person.getNickName() == fakePerson.getNickName() : "

+ (person.getNickName() == fakePerson.getNickName()));

fakePerson.setNickName(0, "compare");

System.out.println(person);

System.out.println(fakePerson);

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

private static class Person implements Cloneable {

private String name;

private String[] nickName;

public Person(String name, String[] nickName) {

this.name = name;

this.nickName = nickName;

}

public void setNickName(int index, String nickName) {

this.nickName[index] = nickName;

}

public void setNickName(String[] nickName) {

this.nickName = nickName;

}

public String[] getNickName() {

return nickName;

}

@Override

public Object clone() throws CloneNotSupportedException {

return super.clone();

}

@Override

public String toString() {

return "Person{" +

"name='" + name + '\'' +

", nickName=" + Arrays.toString(nickName) +

'}';

}

}

調用shallowCopyTest方法,輸出結果為:

person.getNickName() == fakePerson.getNickName() : true

Person{name='ming', nickName=[compare, daMing]}

Person{name='ming', nickName=[compare, daMing]}

可以看到原對象與克隆對象的 nickName 是同一個數組,更改一個以後另一個的值也發送相應變化。

2.3 深拷貝的實作

實作深拷貝要将對象類的所有可變對象都拷貝一遍,然後用拷貝的引用去替換掉原有的引用。

實作例子如下:

private static void deepCopyTest() {

Student ming = new Student("ming", new String[]{"mingMing", "daMing"}, "jiangNan");

compareCloneObject(ming);

}

public static class Student extends Person {

private String school;

public Student(String name, String[] nickName, String school) {

super(name, nickName);

this.school = school;

}

@Override

public Object clone() throws CloneNotSupportedException {

Student student = (Student) super.clone();

student.setNickName(this.getNickName().clone());

return student;

}

@Override

public String toString() {

return "Student{" +

"name='" + super.name + '\'' +

", nickName=" + Arrays.toString(super.nickName) +

", school='" + school + '\'' +

'}';

}

}

調用deepCopyTest方法,輸出結果為:

person.getNickName() == fakePerson.getNickName() : false

Student{name='ming', nickName=[mingMing, daMing], school='jiangNan'}

Student{name='ming', nickName=[compare, daMing], school='jiangNan'}

可以看到兩個對象 nickName 已經不是同一個對象了,改變之後也不會互相影響了。這是因為在覆寫的 clone 方法中對 nickName 數組也進行了克隆,并指派給克隆對象。

3.注釋文檔及個人翻譯

/**

* Creates and returns a copy of this object. The precise meaning

* of "copy" may depend on the class of the object. The general

* intent is that, for any object {@code x}, the expression:

*

* * x.clone() != x

* will be true, and that the expression:

*

* * x.clone().getClass() == x.getClass()

* will be {@code true}, but these are not absolute requirements.

* While it is typically the case that:

*

* * x.clone().equals(x)

* will be {@code true}, this is not an absolute requirement.

*

* 建立并傳回一個對象的拷貝。拷貝的準确定義取決于對象的類定義。普遍的來說,對任意對象 x,

* 表達式:x.clone() ! = x 的值是 true,并且表達式:x.clone().getClass() == x.getClass()

* 的值是

* true,但這些要求并不是絕對的。并且通常表達式:x.clone().equals(x)的值也是 true,

* 這也不是絕對必要的條件。

*

* By convention, the returned object should be obtained by calling

* {@code super.clone}. If a class and all of its superclasses (except

* {@code Object}) obey this convention, it will be the case that

* {@code x.clone().getClass() == x.getClass()}.

*

* 按照慣例,應該通過調用 super.clone 來擷取傳回的對象。如果一個類及其所有超類(Object 除外)

* 都遵循此約定,則 x.clone().getClass() == x.getClass() 成立。

*

* By convention, the object returned by this method should be independent

* of this object (which is being cloned). To achieve this independence,

* it may be necessary to modify one or more fields of the object returned

* by {@code super.clone} before returning it. Typically, this means

* copying any mutable objects that comprise the internal "deep structure"

* of the object being cloned and replacing the references to these

* objects with references to the copies. If a class contains only

* primitive fields or references to immutable objects, then it is usually

* the case that no fields in the object returned by {@code super.clone}

* need to be modified.

*

* 按照慣例,被本方法傳回的對象應該與被克隆的原本對象無關。為了實作這種獨立,可能需要在

* 克隆方法傳回前修改被傳回對象的字段。通常,這意味着拷貝構成被克隆對象的内部“深度結構”

* 的任何可變對象,并用拷貝的引用替換掉原本對象的引用。如果一個類僅僅包含原始字段或不可

* 變對象的引用,那麼通常super.clone傳回對象中沒有字段需要被修改。

*

* The method {@code clone} for class {@code Object} performs a

* specific cloning operation. First, if the class of this object does

* not implement the interface {@code Cloneable}, then a

* {@code CloneNotSupportedException} is thrown. Note that all arrays

* are considered to implement the interface {@code Cloneable} and that

* the return type of the {@code clone} method of an array type {@code T[]}

* is {@code T[]} where T is any reference or primitive type.

* Otherwise, this method creates a new instance of the class of this

* object and initializes all its fields with exactly the contents of

* the corresponding fields of this object, as if by assignment; the

* contents of the fields are not themselves cloned. Thus, this method

* performs a "shallow copy" of this object, not a "deep copy" operation.

*

* Object 類的 clone 方法執行特定的克隆操作。首先,如果對象的類沒有實作 Cloneable

* 接口,那麼會抛出 CloneNotSupportedException 異常。請注意,所有的數組都被視為實

* 現了 Cloneable 接口,并且 T[] 類型數組 clone 接口的傳回類型是 T[],此處 T 可以

* 是任意引用類型或原始類型。除此之外,此方法建立一個對象的類的新執行個體,然後用原本對象對

* 應字段内容來初始化新執行個體所有字段,就像指派;字段的内容不會被克隆。是以,此方法對對象

* 執行了“淺拷貝”而不是一個“深拷貝”。

*

* The class {@code Object} does not itself implement the interface

* {@code Cloneable}, so calling the {@code clone} method on an object

* whose class is {@code Object} will result in throwing an

* exception at run time.

* Object 類自身沒有實作 Cloneable 接口,是以當對一個 Object 類的執行個體調用 clone

* 方法時将會在運作時抛出異常。

* @return a clone of this instance.

* @throws CloneNotSupportedException if the object's class does not

* support the {@code Cloneable} interface. Subclasses

* that override the {@code clone} method can also

* throw this exception to indicate that an instance cannot

* be cloned.

* @see java.lang.Cloneable

*/

protected native Object clone() throws CloneNotSupportedException;