Cloneable接口是一個標記接口,也就是沒有任何內容,定義如下:
這裏分析一下這個接口的用法,clone方法是在Object種定義的,而且是protected型的,只有實現了這個接口,纔可以在該類的實例上調用clone方法,否則會拋出CloneNotSupportException。Object中默認的實現是一個淺拷貝,也就是表面拷貝,如果需要實現深層次拷貝的話,必須對類中可變域生成新的實。
Object提供了一個對象拷貝的默認方法clone方法,但是該方法是有缺陷的,它提供了一種淺拷貝方式,也就是它並不會把對象所有屬性全部拷貝一份,而是有選擇性的拷貝,拷貝規則如下:
1、基本類型
如果變量是基本類型,則拷貝其值,比如:int、float、long等。
2、String字符串
這個比較特殊,拷貝的是地址,是個引用,但是在修改的時候,它會從字符串池(String Pool)中重新生成新的字符串,原有的字符串對象保持不變,此處可以認爲String是個基本類型。
3、對象
如果變量時一個實例對象,則拷貝地址引用,也就是說此時新拷貝出的對象與原有對象共享該實例變量,不受訪問權限的限制。這在Java中很瘋狂,因爲它突破了訪問權限的定義,一個private修飾的變量,竟然可以被兩個實例對象訪問。
public class Client { public static void main(String[] args){ //定義父親 Person p = new Person("父親"); //定義大兒子 Person son1 = new Person("大兒子",p); //定義小兒子 Person son2 = son1.clone(); //重新給son2起名 son2.setName("小兒子"); //給小兒子,找個乾爹 son2.getFather().setName("乾爹"); System.out.println(son1.getName()+" 的父親是 "+son1.getFather().getName()); System.out.println(son2.getName()+" 的父親是 "+son2.getFather().getName()); } } class Person implements Cloneable{ private String name; private Person father; public Person(String name){ this.name=name; } public Person(String name,Person father){ this.name=name; this.father=father; } //拷貝的實現 @Override public Person clone(){ Person p = null; try{ //調用Object的淺拷貝 p = (Person) super.clone(); /** * 1.重新覆寫對象實例部分的拷貝,實現深拷貝 * 2.如果沒有重寫對象實例部分的拷貝,那麼大兒子和小兒子的父親會引用同一個父親, * 只要任意修改一下父親,另外一個就會被修改 */ p.setFather(new Person(p.getFather().getName())); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return p; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person getFather() { return father; } public void setFather(Person father) { this.father = father; } }