2015-02-11 54 views
-4

當對象沒有實際實現接口時,您可以將對象轉換爲接口嗎?例如:將對象投射到未實現的接口

矩形類不實現可食用

Rectangle cerealBox = new Rectangle(); 
Edible e; 
e = (Edible) cerealBox; 

是這有效嗎?

+4

你爲什麼不試試? – 2015-02-11 00:14:49

+4

在這裏問一個可能的錯誤答案或混淆答案的答案,而不是直接嘗試並直接得到正確的答案是否更有效率? – EJP 2015-02-11 00:16:14

回答

0

不可以。因爲接口沒有實現,你會得到一個ClassCastException。

2

這將編譯,但您將在運行時得到ClassCastException,因爲Rectangle不會執行Edible

爲什麼這甚至編譯?畢竟,編譯器可以確定Rectangle沒有實現Edible。因爲參考變量cerealBox可以在任何時候參考Rectangle的一些未知子類,它們實現了Edible

public class EdibleRectangle extends Rectangle implements Edible { 
    //... 
} 

所以編譯器必須允許投,但類型將在運行時進行檢查,導致ClassCastException如果不是Edible

請注意,如果你讓Edible一類,甚至abstract,那麼編譯器會生成就投一個錯誤,因爲它確定一個Rectangle不能是Edible,因爲Rectangle不繼承Edible。因爲Java不允許擴展多個類,所以Rectangle的任何子類都可以是Edible

還要注意的是,如果你做Rectanglefinal,那麼編譯器會生成就投一個錯誤,因爲可以有沒有RectangleEdibleRectangle上述子類可以實現Edible接口。

0

在這種情況下編譯器不會抱怨,如果你寫這個,但是在運行時你會得到一個未經檢查的運行時異常:特別是ClassCastException。未經檢查的運行時異常通常會由於完全可預防的錯誤代碼而指示異常 - 在這種情況下,可能會阻止非法投射。

如何防止此異常?

如果您必須將一個變量類型轉換爲另一個變量類型,則爲了防範此異常,應首先使用類型比較運算符instanceof執行檢查。例如:

if (cerealBox instanceof Edible) { 
    Edible e = (Edible) cerealBox; 
    // munch away 
} 
else { 
    // spit it out - it's not edible (or there's nothing there) 
} 

該檢查將只返回true如果變量是針對被測試的類型(或類型的子類型),或者如果它被實現對所測試的接口。如果變量是null它將返回false

爲什麼編譯器會讓你做危險的事情?

如果被投射的類型未被標記爲final並且該投射屬於界面,編譯器將不會爲可能非法演員提供錯誤。這是因爲:

  • 代碼旨在爲可擴展的,所以未來的開發人員可以隨時添加的Rectangle新亞型,這可能最終會被賦給變量cerealBox:變量是多態性;和
  • Rectangle的任何這樣的子類型可以實施Edible

因此應該允許這種轉換(參見下面的例子)。程序員應該使用instanceof來防止ClassCastException

public class Soggy extends Rectangle implements Edible {} 
... 
// cerealBox is actually Soggy: it is polymorphic 
Rectangle cerealBox = new Soggy(); 
if (cerealBox instanceof Edible) 
    Edible e = (Edible) cerealBox; 

編譯器會給出錯誤用於如果石膏:

  1. 源類型被標記final,也不它或它的超類型實現該接口被鑄造到;

    public class Card {} // not edible 
    public final class Rectangle extends Card {} // final, not edible 
    ... 
    Rectangle cerealBox = new Rectangle(); 
    Edible e = (Edible) cerealBox; // won't compile 
    
  2. 鑄件是一類,並且源類型不是那類的子類型。

    public class Circle {} 
    // neither this nor its subtypes will ever be Circle 
    public class Rectangle {} 
    ... 
    Rectangle cerealBox = new Rectangle(); 
    Circle e = (Circle) cerealBox; // won't compile 
    

在這兩種情況下,編譯器可以告訴該轉換將是非法的,無論你的代碼的任何潛在的延伸。因此它阻止你這樣做。

參考文獻: