2012-08-30 49 views
4

當編寫一個泛型方法來處理表單數據時,我遇到了以下(正如我所看到的)未經處理的行爲。給出下面的代碼:爲什麼泛型方法在賦值中更改參數化類型?

public class Test { 
    public <T> void someGenericMethod(Integer a) { 
     @SuppressWarnings("unchecked") 
     T t = (T) a; 
     System.out.println(t); 
     System.out.println(t.getClass()); 
    } 

    public static void main(String[] args) { 
     Test test = new Test(); 
     test.<BigDecimal>someGenericMethod(42); 
    } 
} 

AFAIK,上述代碼應生成在管線T t = (T) a一個ClassCastException因爲在主方法調用被設置參數化類型BigDecimal和從Integer爲BigDecimal鑄造是不允許的,相反地我所料,該程序執行好並打印以下內容:

42 
class java.lang.Integer 

事實上,如果我添加其他參數的方法簽名(像String b)再拍分配新建分配FY T t2 = (T) b,程序打印

42 
class java.lang.String 

爲什麼t變量改變它的類型Integer(是,任何機會,使一些種推廣的T類型爲Object)?

對這種行爲作出任何解釋,歡迎

回答

3

(T) a選中投:由於type erasure,運行時無法知道什麼類型的T的方式,所以它實際上並不能檢查,如果a屬於鍵入T

當你這樣做時,編譯器發出警告;在你的情況下,你通過編寫@SuppressWarnings("unchecked")來壓制這個警告。


編輯以(響應進一步的問題在下面的評論)添加

如果您要檢查的轉換,你可以這樣寫:

public class Test { 
    public <T> void someGenericMethod(Class<T> clazz, Integer a) { 
     T t = clazz.cast(a); 
     System.out.println(t); 
     System.out.println(t.getClass()); 
    } 

    public static void main(String[] args) { 
     Test test = new Test(); 
     // gives a ClassCastException at runtime: 
     test.someGenericMethod(BigDecimal.class, 42); 
    } 
} 

通過通過clazz,您允許運行時檢查演員;而且,你還允許編譯器從方法參數中推斷出T,所以你不必再寫test.<BigDecimal>someGenericMethod了。

當然,調用該方法通過使用一個未經檢查的投仍然可以繞過這個代碼:

public static void main(String[] args) { 
    Test test = new Test(); 
    Class clazz = Object.class; 
    test.someGenericMethod((Class<BigDecimal>) clazz, 42); 
} 

但隨後這main的錯,不是someGenericMethod的。 :-)

+0

是的,是一個未經檢查的演員,但爲什麼不扔'ClassCastException'而不是改變'T'到'Object'的類型? – higuaro

+1

因爲這是一個未經檢查的演員。運行時無法檢查演員表的有效性。如果運行時可以檢查轉換,它會看到它是無效的,並拋出一個'ClassCastException';但它不能,所以它不會,也不會。我不知道你爲什麼期望別的。 – ruakh

+0

幾乎未經檢查的轉換的_definition_是,如果在運行時已知完整類型信息,它將無法檢查是否拋出了「ClassCastException」。 –

2

編譯時,你的代碼基本上上方成爲以下的非泛型方法:

public void someGenericMethod(Integer a) { 
    Object t = a; 
    System.out.println(t); 
    System.out.println(t.getClass()); 
} 

沒有投。沒有例外。

+0

謝謝,所以''是沒用的,如果你不在方法簽名中添加一個類型爲'T'的參數...... – higuaro

1

您在方法簽名中指定了一個類型參數,但從不使用它。

我想你想是這樣的:

public class Test { 
    public <T> void someGenericMethod(T someItem) { 
     System.out.println(someItem); 
     System.out.println(someItem.getClass()); 
    } 
} 

public static void main(String[] args) { 
    Test test = new Test(); 
    BigDecimal bd = new BigDecimal(42); 

    test.someGenericMethod(42); // Integer 
    test.someGenericMethod("42"); // String 
    test.someGenericMethod(42L); // Long 
    test.someGenericMethod(bd); // BigDecimal 
} 

注意,有沒有必要投。

參數類型是在方法簽名聲明和從參數推斷。

在你的代碼中,你正在參數化方法調用(我從來沒有見過)並傳入一個int。

它還挺很難理解你想要做什麼,因爲你的示例代碼什麼也不做。

相關問題