2013-07-11 118 views
5

假設有下面的代碼:爲什麼在反射投射時隱式投射工作會拋出異常?

@SuppressWarnings("unchecked") 
public static <T> T implicitCaster(Class<T> cls, Object o) { 
    return (T) o; 
} 

public static <T> T reflectionCaster(Class<T> cls, Object o) { 
    return cls.cast(o); 
} 

代碼將按預期在這兩種情況下,以下情況例外,在原語發現:

public static void main(String[] args) { 
    System.out.println(implicitCaster(int.class, 42)); 
    System.out.println(reflectionCaster(int.class, 42)); 
} 

第一次調用工作正常,但第二個電話投擲java.lang.ClassCastException

這是一個忽視自動裝箱的案例嗎?還是不可能在這種情況下提供反射鑄造的自動裝箱? 還是有其他的東西導致這種不一致?

編輯:調用此代碼按預期工作:

public static void main(String[] args) { 
    System.out.println(implicitCaster(Integer.class, 42)); 
    System.out.println(reflectionCaster(Integer.class, 42)); 
} 

回答

3

這是因爲類型擦除。

在運行時,泛型類型參數不存在。
將對象轉換爲泛型類型參數不起作用。 (這就是爲什麼你會得到未經檢查的投射警告)

因此,你的第一行自動複選框42Object傳遞給該方法。
該函數然後返回Object,該函數傳遞給System.out.println


你的第二個電話呼叫int原始類型的cast方法。
這會引發異常,因爲對象不能轉換爲基元類型。 (自動裝箱是一個純粹的編譯時功能,因此它並不能幫助)

錯誤發生時cast()checks isInstance(),以驗證轉換是有效的。

isInstance() say該文檔:

具體地,如果該Class對象表示一個聲明的類,該方法如果指定的Object參數是表示類的一個實例,則返回true(或者其任何亞類的) ;否則返回false。如果此Class對象表示一個數組類,則如果通過標識轉換或擴展引用轉換將指定的Object參數轉換爲數組類的對象,則此方法返回true;否則返回false。如果此Class對象表示一個接口,則此方法在指定Object參數的類或任何超類實現此接口時返回true;否則返回false。 如果此Class對象表示一個基本類型,則此方法返回false。

(強調)


你的編輯工作,因爲你不再使用基本類型。
在這兩種情況下,編譯器自動包裝42,以便它可以作爲對象傳遞。

第一個電話,和以前一樣,沒有任何效果。
第二次調用驗證盒裝整數實際上是Integer類的實例,然後將其返回。

+0

我寫過那裏的代碼適用於每個給定的類,除了原語;因此可以將對象轉換爲泛型類型。其次,你可以將對象投射到基元。 – m3th0dman

+0

@ m3th0dman:我沒有說這是不可能的。我說它在運行時沒有效果。 – SLaks

+0

我現在明白了;但是這種違背了投射法的合同?技術上來說,演員是可能的。 – m3th0dman