您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Java克隆對象的特性是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
在java面向?qū)ο蟮木幊坍?dāng)中,要復(fù)制引用類型的對象,就必須克隆對象。通過調(diào)用對所有引用類型和對象都是可用的clone方法,來實現(xiàn)克隆。
在Java中傳值及引伸深度克隆的思考中,我們講過引申到克隆技術(shù)Java中的所有對象都是Object類的子類。我們知道,Java是純面向?qū)ο蟮某绦蛟O(shè)計語言。Java里,所有的類的***父類都是java.lang.Object類,也就是說,如果一個類沒有顯示 申明繼承關(guān)系,它的父類默認(rèn)就是java.lang.Object。
有一個很簡單的方法可以證明這一點,我們寫一個Test類,如下:
public class Test { public void someMethod() { super.clone(); } }
里面調(diào)用了super.clone(),編譯時并不報錯。其實clone()方法為java.lang.Object類提供的一個 protected型方法。
對象克隆
本文通過介紹java.lang.Object#clone()方法來說明Java語言的對象克隆特性。
java.lang.Object#clone()方法由java.lang.Object加以實現(xiàn),主要對對象本身加以克隆。
首先我們看看下面的例子:
public class TestClone { public static void main(String[] args) { MyClone myClone1 = new MyClone("clone1"); MyClone myClone2 = (MyClone)myClone1.clone(); if (myClone2 != null) { System.out.println(myClone2.getName()); System.out.println("myClone2 equals myClone1: " + myClone2.equals(myClone1)); } else { System.out.println("Clone Not Supported"); } } } class MyClone { private String name; public MyClone(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { return null; }}
編譯執(zhí)行TestClone,打印出:
C:\clone>javac *.java C:\clone>java TestClone Clone Not Supported C:\clone>
說明MyClone#clone()方法調(diào)用super.clone()時拋出了CloneNotSupportedException異常,不支持克隆。
為什么父類java.lang.Object里提供了clone()方法,卻不能調(diào)用呢?
原來,Java語言雖然提供了這個方法,但考慮到安全問題, 一方面將clone()訪問級別設(shè)置為protected型,以限制外部類訪問;
另一方面,強制需要提供clone功能的子類實現(xiàn)java.lang.Cloneable接口,在運行期,JVM會檢查調(diào)用clone()方法的 類,如果該類未實現(xiàn)java.lang.Cloneable接口,則拋出CloneNotSupportedException異常。
java.lang.Cloneable接口是一個空的接口,沒有申明任何屬性與方法。該接口只是告訴JVM,該接口的實現(xiàn)類需要開放“克隆”功能。
我們再將MyClone類稍作改變,讓其實現(xiàn)Cloneable接口:
class MyClone implements Cloneable { ...//其余不做改變 } 編譯執(zhí)行TestClone,打印出: C:\clone>javac *.java C:\clone>java TestClone clone1 myClone2 equals myClone1: false C:\clone>
根據(jù)結(jié)果,我們可以發(fā)現(xiàn):
1,myClone1.clone()克隆了跟myClone1具有相同屬性值的對象
2,但克隆出的對象myClone2跟myClone1不是同一個對象(具有不同的內(nèi)存空間)
小結(jié)
如果要讓一個類A提供克隆功能,該類必須實現(xiàn)java.lang.Cloneable接口,并重載 java.lang.Object#clone()方法。
public class A extends Cloneable { public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { //throw (new InternalError(e.getMessage())); return null; } } }
對象的深層次克隆
上例說明了怎么樣克隆一個具有簡單屬性(String,int,boolean等)的對象。
但如果一個對象的屬性類型是List,Map,或者用戶自定義的其他類時,克隆行為是通過怎樣的方式進行的?
很多時候,我們希望即使修改了克隆后的對象的屬性值,也不會影響到原對象,這種克隆我們稱之為對象的深層次克隆。怎么樣實現(xiàn)對象的深層次克隆呢?
驗證對象的克隆方式
為了驗證對象的克隆方式,我們對上面的例子加以改進,如下(為了節(jié)省篇幅,我們省略了setter與getter方法):
public class TestClone { public static void main(String[] args) { //為克隆對象設(shè)置值 MyClone myClone1 = new MyClone("clone1"); myClone1.setBoolValue(true); myClone1.setIntValue(100); //設(shè)置List值 List <Element>listValue = new ArrayList<Element>(); listValue.add(new Element("ListElement1")); listValue.add(new Element("ListElement2")); listValue.add(new Element("ListElement3")); myClone1.setListValue(listValue); //設(shè)置Element值 Element element1 = new Element("element1"); myClone1.setElement(element1); //克隆 MyClone myClone2 = (MyClone)myClone1.clone(); if (myClone2 != null) { //簡單屬性 System.out.println("myClone2.name=" + myClone2.getName() + " myClone2.boolValue=" + myClone2.isBoolValue() + " myClone2.intValue=" + myClone2.getIntValue() ); //復(fù)合屬性(List<Element>與Element) List clonedList = myClone2.getListValue(); Element element2 = myClone2.getElement(); System.out.println("myClone2.listValue.size():" + clonedList.size()); System.out.println("myClone2.element.equals(myClone1.element):" + element2.equals(element1)); System.out.println("myClone2.element.name:" + element2.getName()); //下面我們測試一下myClone2.element是否等于myClone1.element //以及myClone2.listValue是否等于myClone1.listValue //為此,我們修改myClone2.element與myClone2.listValue,如果myClone1的相應(yīng)值也跟著被修改了,則它們引用 的是同一個內(nèi)存空間的變量,我們認(rèn)為它們相等 clonedList.add("ListElement4"); System.out.println("myClone1.listValue.size():" + listValue.size()); element2.setName("Element2"); System.out.println("myClone1.element.name:" + element1.getName()); } else { System.out.println("Clone Not Supported"); } } } class MyClone implements Cloneable { private int intValue; private boolean boolValue; private String name; private List <Element>listValue; private Element element; public MyClone(String name) { this.name = name; } ...//setter與getter方法(略) } class Element implements Cloneable { private String name; public Element (String name) { this.name = name; } ...//setter與getter方法(略) }
編譯執(zhí)行TestClone,打印出:
C:\clone>javac *.java C:\clone>java TestClone myClone2.name=clone1 myClone2.boolValue=true myClone2.intValue=100 myClone2.listValue.size():3 myClone2.element.equals(myClone1.element):true myClone2.element.name:element1 myClone1.listValue.size():4 myClone1.element.name:Element2 09.myClone2 equals myClone1: false 10.C:\clone> 11.
我們發(fā)現(xiàn),對于對象里的List,Element等復(fù)合屬性,super.clone()只是簡單地賦值,沒有采取克隆手段。也就是說,修改被克 隆后的對象值,會影響到原對象。
怎么進行深層次的克隆呢?
答案是,我們只能手動在重載的clone()方法里,對屬性也分別采用克隆操作。當(dāng)然條件是,屬性類也得支持克隆操作
class MyClone implements Cloneable { ... public Object clone() { try { MyClone myClone = (MyClone)super.clone(); //分別對屬性加以克隆操作 myClone.element = this.element.clone(); myClone.listValue = new ArrayList(); for (Element ele:this.listValue) { myClone.listValue.add(ele.clone()); } return myClone; } catch (CloneNotSupportedException e) { return null; } } ... } //讓Element類也支持克隆操作 class Element implements Cloneable { ... public Element clone() { try { return (Element)super.clone(); } catch (CloneNotSupportedException e) { return null; } } }
深層次的克隆操作往往存在效率問題,尤其是需要讓List,Map等集合類也支持深層次的克隆操作時。
“Java克隆對象的特性是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。