[英]Downcasting while calling super.clone() method
考慮以下程序
class A implements Cloneable {
String str = null;
public void set(String str)
{
this.str = str;
}
@Override
public A clone()
{
A a = null;
try {
a = (A) super.clone();
if(a.str!=null) {
System.out.println(a.str);
}
else {
System.out.println("null");
}
}
catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return a;
}
public static void main (String args[])
{
A a = new A();
a.set("1234");
A b = a.clone();
}
}
為什么上述程序的輸出是1234而不是null。
我期待null,因為對我的理解如下。
super.clone()方法將創建一個父類型的新對象(在本例中為Object),其中父類的屬性將被淺復制。
當我們在clone()方法中進行向下轉換時,子類中定義的屬性將使用其默認值進行初始化,因為這是一個新對象。
但是在查看輸出之后,似乎子類(this)的當前實例的屬性值被復制到新構造的對象中(在調用父類的克隆並向下轉換之后)。
有人能告訴我們當我們垂頭喪氣時發生了什么嗎?
正確的結果是1234 ...讓我們看看原因:
創建一個新的A
實例:
A a = new A();
將值設置為A.str
a.set("1234");
A b = a.clone();
首先,請注意,我們正在使用實例a
clone()
方法,所以我們去那里:
@Override
public A clone()
{
// create a NEW instance, it does not set a to null!!!
// to reference the caller (a.clone in main)
// you must use this keyword i.e: this.str = null
A a = null;
try {
// call Cloneable::clone() method
a = (A) super.clone();
// now a is filled with data of this instance so print 1234
if(a.str!=null) {
System.out.println(a.str);
}
// unused code in this case
else {
System.out.println("null");
}
}
catch (CloneNotSupportedException e) {
e.printStackTrace();
}
// return cloned instance
return a;
}
來自Object#clone文檔。
創建並返回此對象的副本。 “復制”的確切含義可能取決於對象的類別。 通常的意圖是,對於任何對象x,表達式:
x.clone()!= x
將為真,並且該表達式:
x.clone()。getClass()== x.getClass()
是正確的,但這不是絕對要求。 通常情況是:
x.clone()。equals(x)
是真的,這不是絕對要求。
如您所見,典型的情況是X.equals(XClone) == true
。 對於您而言,情況並非如此,因為A
沒有覆蓋equals
方法。
另外:
類Object的方法clone執行特定的克隆操作。
[...]
該方法創建該對象類的新實例,並使用該對象相應字段的內容完全初始化其所有字段,就像通過賦值一樣; 字段的內容本身不會被克隆。 因此,此方法執行此對象的“淺復制”,而不是“深復制”操作。
如本文檔所述,本機實現只是創建您要克隆的對象的shallow copy
。 由於這種行為,正確的輸出是1234
而不是null
,因為類中的fields
只是分配給了克隆的實例。
super.clone()方法將創建一個父類型的新對象(在這種情況下為Object)
不,這是您要出問題的地方。 Object.clone()
將創建一個新的實例,該實例與調用它的對象的運行時類相同,該運行時類是A
,而不是Object
。 它將把被調用對象中A
所有字段淺拷貝到新對象中。
當我們在clone()方法中進行向下轉換時,子類中定義的屬性將使用其默認值進行初始化,因為這是一個新對象。
這沒有任何意義,因為強制轉換引用將永遠不會影響所指向對象的狀態。 如果引用所指向的對象還不是A
的實例,則強制轉換將拋出ClassCastException
。 如果強制轉換成功,則意味着引用指向的對象已經是A
的實例,而您只是使用不同類型的引用指向同一對象。 您將永遠不會獲得帶有演員表的“新對象”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.