當對象沒有實際實現接口時,您可以將對象轉換爲接口嗎?例如:將對象投射到未實現的接口
矩形類不實現可食用
Rectangle cerealBox = new Rectangle();
Edible e;
e = (Edible) cerealBox;
是這有效嗎?
當對象沒有實際實現接口時,您可以將對象轉換爲接口嗎?例如:將對象投射到未實現的接口
矩形類不實現可食用
Rectangle cerealBox = new Rectangle();
Edible e;
e = (Edible) cerealBox;
是這有效嗎?
不可以。因爲接口沒有實現,你會得到一個ClassCastException。
這將編譯,但您將在運行時得到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
。
還要注意的是,如果你做Rectangle
final
,那麼編譯器會生成就投一個錯誤,因爲可以有沒有Rectangle
如EdibleRectangle
上述子類可以實現Edible
接口。
在這種情況下編譯器不會抱怨,如果你寫這個,但是在運行時你會得到一個未經檢查的運行時異常:特別是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;
編譯器會給出錯誤用於如果石膏:
源類型被標記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
鑄件是一類,並且源類型不是那類的子類型。
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
在這兩種情況下,編譯器可以告訴該轉換將是非法的,無論你的代碼的任何潛在的延伸。因此它阻止你這樣做。
參考文獻:
ClassCastException
docsinstanceof
:Java教程>平等關係,和條件運算>The Type Comparison Operator instanceof
你爲什麼不試試? – 2015-02-11 00:14:49
在這裏問一個可能的錯誤答案或混淆答案的答案,而不是直接嘗試並直接得到正確的答案是否更有效率? – EJP 2015-02-11 00:16:14