在實際程式設計過程中,我們常常要遇到這種情況:有一個對象 A,在某一時刻 A 中已經包含了一些有效值,此時可能會需要一個和 A 完全相同新對象 B,并且此後對 B 任何改動都不會影響到 A 中的值,也就是說, A 與 B 是兩個獨立的對象,但 B 的初始值是由 A 對象确定的。在 Java 語言中,用簡單的指派語句是不能滿足這種需求的。因為java中的指派語句采用的是值傳遞,即多個棧空間(屬性名)引用同一片堆空間記憶體,對其中一個屬性修改,勢必影響到所有引用該堆空間對象的屬性。
要滿足這種需求雖然有很多途徑,但采用clone()方法是其中最簡單,也是最高效的手段.。
protected native Object clone() throws CloneNotSupportedException;
clone方法是Object類中的一個方法,可以通過clone進行對象的拷貝操作。
1. Cloneable接口
如果想要使用clone方法,單純的覆寫Object的clone方法是不能使用的,他會抛出一個CloneNotSupportedException異常。
要想正确使用,該對象的類要實作一個Cloneable辨別接口。
public interface Cloneable {
}
Cloneable接口中沒有任何方法,它存在的意義就是允許其實作類使用clone方法。是以正确的使用流程應該是這樣的:
class Person implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Cloneable接口位于java.lang 包中,java.lang包已經被預設的導入類中,是以不需要寫成java.lang.Cloneable。
2. clone和new的差別
new 操作符的本意是在堆上開辟記憶體。程式執行到 new 操作符時,首先去看 new 操作符後面的類型,因為知道了類型,才能知道要配置設定多大的記憶體空間。配置設定完記憶體之後,再調用構造函數,填充對象的各個域,這一步叫做對象的初始化,構造方法傳回後,一個對象建立完畢,可以把他的引用(位址)釋出到外部,在外部就可以使用這個引用操縱(屬性名)這個對象。
clone 在第一步是和 new 相似的,都是配置設定記憶體,調用 clone 方法時,配置設定的記憶體和原對象(即調用 clone 方法的對象)相同,然後再使用原對象中對應的各個域,填充新對象的域,填充完成之後, clone 方法傳回,一個新的相同的對象被建立,這時我們就可以在外部對其進行通路。
在前面clone方法的定義中我們可以看到,clone是一個native本地方法,native方法的效率一般來說都是遠高于java中的非native方法。是以一般我們使用clone方法,直接調用super.clone()即可。
3. clone方法的使用
class Person implements Cloneable {
public int age;
public String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class Demo {
public static void main(String[] args) {
Person person1 = new Person(, "xucc");
Person person2 = null;
try {
person2 = (Person) person1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
person1.age = ;
person1.name = "licc";
System.out.println(person1);
System.out.println(person2);
}
}
運作結果:
com.xucc.exercise.Person@282ba1e
Person{age=, name='licc'}
com.xucc.exercise.Person@30c7da1e
Person{age=, name='xucc'}
我們可以看出,clone确實開辟了新的空間,并且得到了與原有對象相同的值。
最後,我們應該注意的是,clone()雖然建立了新的對象開辟了新的記憶體空間,但是對象中包含的一些屬性,并沒有進行重新建立,例如字元串,還是會從共享池中複用,是以clone屬于淺拷貝。
關于進一步的分析會在之後的文章中展現。