不是你的類型

出自《java puzzle》


本謎題要測試你對Java的兩個最經典的操作符:instanceof和轉型的理解程度。下面的三個程序每一個都會做些什麼呢?

public class Type1 {
public static void main(String[] args) {
String s = null;
System.out.println(s instanceof String);
}
}
public class Type2 {
public static void main(String[] args) {
System.out.println(new Type2() instanceof String);
}
}
public class Type3 {
public static void main(String args[]) {
Type3 t3 = (Type3) new Object();
}
}

第一個程序,Type1,展示了instanceof操作符應用於一個空對象引用時的行爲。儘管null對於每一個引用類型來說都是其子類型,但是instanceof操作符被定義爲在其左操作數爲null時返回false。因此,Type1將打印false。這被證明是實踐中非常有用的行爲。如果instanceof告訴你一個對象引用是某個特定類型的實例,那麼你就可以將其轉型爲該類型,並調用該類型的方法,而不用擔心會拋出ClassCastExceptionNullPointerException異常。

第二個程序,Type2,展示了instanceof操作符在測試一個類的實例,以查看它是否是某個不相關的類的實例時所表現出來的行爲。你可能會期望該程序打印出false。畢竟,Type2的實例不是String的實例,因此該測試應該失敗,對嗎?不,instanceof測試在編譯時刻就失敗了,我們只能得到下面這樣的出錯消息:
Type2.java:3: inconvertible types
found : Type2, required: java.lang.String
System.out.println(new Type2() instanceof String);
^
該程序編譯失敗是因爲instanceof操作符有這樣的要求:如果兩個操作數的類型都是類,其中一個必須是另一個的子類型[JLS 15.20.2, 15.16, 5.5]。Type2和String彼此都不是對方的子類型,所以instanceof測試將導致編譯期錯誤。這個錯誤有助於讓你警惕instanceof測試,它們可能並沒有去做你希望它們做的事情。

第三個程序,Type3,展示了當要被轉型的表達式的靜態類型是轉型類型的超類時,轉型操作符的行爲。與instanceof操作相同,如果在一個轉型操作中的兩種類型都是類,那麼其中一個必須是另一個的子類型。儘管對我們來說,這個轉型很顯然會失敗,但是類型系統還沒有強大到能夠洞悉表達式new Object()的運行期類型不可能是Type3的一個子類型。因此,該程序將在運行期拋出ClassCastException異常。這有一點違背直覺:第二個程序完全具有實際意義,但是卻不能編譯;而這個程序沒有任何實際意義,但是卻可以編譯。

總之,第一個程序展示了instanceof運行期行爲的一個很有用的冷僻案例。第二個程序展示了其編譯期行爲的一個很有用的冷僻案例。第三個程序展示了轉型操作符的行爲的一個冷僻案例,在此案例中,編譯器並不能將你從你所做荒唐的事中搭救出來,只能靠VM在運行期來幫你繃緊這根弦。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章