阿里面試官問題:
談談你對java中的深克隆和淺克隆的理解
回答:
#(說明:本文針對深克隆和淺克隆的區別和實現方式?這個問題)
Talk is cheap
#最近不只一次遇見深淺克隆(深複製,淺複製)的問題,除了印像中有個clone方法外一臉懵逼! ! !克隆(複製)在Java中是一種常見的操作,目的是快速取得一個物件副本。克隆分為深克隆和淺克隆。
淺克隆:建立一個新對象,新對象的屬性和原來對象完全相同,對於非基本型別屬性,仍指向原有屬性所指向的對象的記憶體位址。
深克隆:建立一個新對象,屬性中引用的其他對像也會被克隆,不再指向原有對象位址。
總之深淺克隆都會在堆中新分配一塊區域,差異在於物件屬性所引用的物件是否需要進行複製(遞歸性的)。
Show you my picture
#pos:目前物件的位址;
son:son屬性所指向的位址;
name:物件的name屬性。
(相關推薦:java入門教學)
Show you my code
#case1:
public class Son implements Serializable , Cloneable{ private String name; private Son son; public Son() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } @Override public String toString() { return super.toString(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
測試
public static void main(String[] args) throws Exception{ // 创建父亲(LiLiu),儿子(LiWu),孙子(LiLiu)并关联 Son father = new Son(); father.setName("LiSi"); Son son = new Son(); son.setName("LiWu"); Son grandSon = new Son(); grandSon.setName("LiLiu"); father.setSon(son); son.setSon(grandSon); // 调用clone方法 Son fatherCopy = (Son) father.clone(); boolean flag1 = fatherCopy==father; boolean flag2 = fatherCopy.getSon() == son; boolean flag3 = fatherCopy.getSon().getSon() == grandSon; // 比较克隆后的地址 System.out.println(flag1);// false System.out.println(flag2);// true System.out.println(flag3);// true // 比较Name flag1= fatherCopy.getName()==father.getName(); flag2 = fatherCopy.getSon().getName() == son.getName(); flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName(); System.out.println(flag1);// true System.out.println(flag2);// true System.out.println(flag3);// true //将对象写到流里 ByteArrayOutputStream byteOut=new ByteArrayOutputStream(); ObjectOutputStream objOut=new ObjectOutputStream(byteOut); objOut.writeObject(father); //从流里读出来 ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream objInput=new ObjectInputStream(byteIn); fatherCopy = (Son) objInput.readObject(); flag1= fatherCopy==father; flag2 = fatherCopy.getSon() == son; flag3 = fatherCopy.getSon().getSon() == grandSon; System.out.println(flag1);// false System.out.println(flag2);// false System.out.println(flag3);// false // 比较Name flag1= fatherCopy.getName()==father.getName(); flag2 = fatherCopy.getSon().getName() == son.getName(); flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName(); System.out.println(flag1);// false System.out.println(flag2);// false System.out.println(flag3);// false}
從上文程式碼及運行結果不難看出,如果物件實作Cloneable並重寫clone方法不進行任何操作時,呼叫clone是進行的淺克隆。而使用物件流將物件寫入流然後再讀出是進行的深克隆。
思考:既然實作Cloneable介面並重寫clone介面只能進行淺克隆。但如果類別的參考型別屬性(以及屬性的參考型別屬性)都進行淺克隆,直到沒有引用型別屬性或引用型別屬性為null時,整體上就形成了深克隆。既物件的參考型別屬性和屬性的應用型別屬性都實作Coloneable,重寫clone方法並在clone方法中進行呼叫。
protected Object clone() throws CloneNotSupportedException { Son result = (Son) super.clone(); if (son != null) { result.son = (Son) son.clone(); } return result; }
個人認為,在選擇深克隆方法時,應根據物件的複雜程度,如引用類型屬性是否有多層引用類型屬性關係。若物件只有一層或兩層引用類型的屬性,選擇思考中所提到的方法較為方便,反之則使用物件流。
更多相關面試題請上:java面試題目及答案
以上是談談你對java中的深克隆和淺克隆的理解的詳細內容。更多資訊請關注PHP中文網其他相關文章!