2008-12-30 146 views
5

喂所有,「動態」鑄造

想知道是否有任何Java黑客誰可以給我介紹的,爲什麼下面不工作:

public class Parent { 
    public Parent copy() { 
     Parent aCopy = new Parent(); 
     ... 
     return aCopy; 
    } 
} 

public class ChildN extends Parent { 
    ... 
} 

public class Driver { 
    public static void main(String[] args) { 
     ChildN orig = new ChildN(); 
     ... 
     ChildN copy = orig.getClass().cast(orig.copy()); 
    } 
} 

的代碼非常開心編譯,但決定在運行時拋出一個ClassCastException D =

編輯:哇,真的很快回復。多謝你們!所以看起來我不能使用這種方法downcast ...是否有任何其他方式在Java中進行向下轉換?我確實想過讓每個ChildN課程都覆蓋copy(),但並不熱衷於添加額外的樣板代碼。

+0

你可以做到這一點。看看我的編輯。我雖然在第一時間理解「鑄造」有困難。 – OscarRyz 2008-12-30 22:06:31

回答

1

(無法在評論中添加代碼,所以我要在此添加)

關於Cloneable:如果您要實現Cloneable,請按如下方式實施:更清潔打電話......

public class Foo implements Cloneable { 
    public Foo clone() { 
     try { 
      return (Foo) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      return null; // can never happen! 
    } 
} 

[編輯:我也看到其他人使用

throw new AssertionError("This should never happen! I'm Cloneable!"); 
在catch塊

]

6

演員被有效試圖做到這一點:

ChildN copy = (ChildN) orig.copy(); 

(它的工作了劇組在執行時進行,但是這將是什麼,因爲orig.getClass()ChildN.class)但是,orig.copy()不返回一個ChildN的實例,它返回的只是Parent的一個實例,所以它不能被轉換爲ChildN

4

如果ChildN沒有覆蓋副本()返回ChildN的實例,那麼你想垂頭喪氣型親本的目的是鍵入ChildN

9

就像是試圖做到這一點:

public Object copy(){ 
     return new Object(); 
    } 

然後嘗試:

String s = (String) copy(); 

家長類和ChildN級有作爲對象字符串的關係一樣

爲了使它工作,你需要做到以下幾點:

public class ChildN extends Parent { 
    public Parent copy() { 
     return new ChildN(); 
    } 
} 

也就是說,覆蓋「複製」的方法,並返回正確的實例。


編輯

根據您的編輯。這實際上是可能的。這可能是一種可能的方法:

public class Parent { 
    public Parent copy() { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 

這樣你就不必在每個子類中重寫「copy」方法。這是原型設計模式。

但是使用這個實現你應該知道兩個檢查的異常。這是編譯和運行沒有問題的完整程序。

public class Parent { 
    public Parent copy() throws InstantiationException, IllegalAccessException { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 
class ChildN extends Parent {} 

class Driver { 
    public static void main(String[] args) throws InstantiationException , IllegalAccessException { 
     ChildN orig = new ChildN(); 
     ChildN copy = orig.getClass().cast(orig.copy()); 
     System.out.println("Greetings from : " + copy); 
    } 
} 
+0

以身作則!這個答案對我來說很清楚。現在可以聲明Child.copy來返回一個ChildN iso一個Parent嗎? (我知道它可以在C++中) – xtofl 2008-12-30 21:00:25

+0

不在Java中。至少不在Java源代碼中。若要將問題稍微混淆,可以在Java字節碼中允許* – 2008-12-30 21:18:21

+1

Java 5+中的源代碼允許使用它。 – 2008-12-30 21:35:30

2

java.lang.Class#cast(Object)如果Class#isInstance()返回false,則拋出ClassCastException。根據JavaDoc該方法:

確定指定對象是與該Class表示的對象 賦值兼容。此方法 是Java語言 instanceof操作的動態等效... 具體地,如果此 Class對象表示 聲明的類,該方法返回 true如果指定 Object參數是表示類的一個實例 (或其任何子類的 );否則返回 false

因爲Parent不是子類的子類,所以isInstance()返回false,所以cast()拋出異常。這可能會違反最不驚人的原則,但它按照記錄的方式工作 - cast()只能向上播放,而不能向下播放。

2

難道你只是想要你的對象的複製/克隆。

在這種情況下,請根據需要實現Cloneable接口並覆蓋clone()。

public class Parent implement Cloneable { 
    public Object clone() throws CloneNotSupportedException { 
    Parent aCopy = (Parent) super.clone(); 
    ... 
    return aCopy; 
    } 
} 

public class ChildN extends Parent { 
    ... 
} 

public class Driver { 
    public static void main(String[] args) { 
     ChildN orig = new ChildN(); 
     ... 
     ChildN copy = orig.getClass().cast(orig.clone()); 
    } 
} 

這正是您的「copy()」方法嘗試以Java方式執行的操作。

(是的,你可以做花哨的反省遊戲太多,但這些方法失敗或很快變得醜陋,你沒有一個公共默認構造函數。克隆可以在任何情況下,無論是什麼構造你。)

0

之所以向下轉換不工作是因爲,當您將父對象轉換爲子類型時,您無法在父對象上調用子類型的方法。但它以另一種方式工作...