2012-12-20 71 views
9

我從Joshua Bloch給出的谷歌I/O益智遊戲中獲得了這個。下面的代碼Java泛型刪除方法參數

public class Glommer<T> { 
     String glom(Collection<?> obj){ 
     String result = ""; 
     for(Object o : obj){ 
       result += o; 
     } 
     return result; 
     } 

     int glom(List<Integer> ints){ 
      int result = 0; 
      for(int i : ints){ 
       result += i; 
      } 
      return result; 
     } 

     public static void main(String args[]){ 
      List<String> strings = Arrays.asList("1", "2", "3"); 
      System.out.println(new Glommer().glom(strings)); 
     } 

這主要方法拋出一個異常,因爲new Glommer是原始類型,因此在Glommer所有的仿製藥將被刪除,所以它最終調用int glom(List<Integer> ints)而非String glom(Collection<?> obj)

我的問題是,即使我叫glom()new Glommer<Integer>().glom(strings)它不應該叫int glom(List<Integer> ints)方法,因爲由於類型擦除,這種方法實際上是int glom(List ints)stringsListCollection類型的?

回答

7

被調用的方法是在編譯時定義的,而不是在運行時定義的。

如果向構造函數調用添加一個參數,編譯器將獲得足夠的信息來知道它必須調用第一個方法。否則,就好像泛型不存在一樣。在這兩種情況下,被調用的方法在運行時總是保持不變。

編輯一些人懷疑,所以這裏是另一個例子:

public class Test { 

    private static void test(Object object) { 
     System.out.println("Object method"); 
    } 

    private static void test(Integer integer) { 
     System.out.println("Integer method"); 
    } 

    public static void main(String[] args) { 
     Object object = Integer.valueOf(0); 
     test(object); 
    } 

} 

結果是:

Object method 

您的整數關口,以你的方法,但所有的編譯器知道在編譯時間是它是一個對象。即使對象實際上是一個Integer,jvm也不會自動更改方法調用。

+0

我想說編譯器確定要執行的方法的簽名,但是在運行時使用實際對象類型選擇要執行的方法。 – tcb

+0

@tcb我加了個例子,試試吧。 – WilQu

+0

我明白你想說什麼,在這個例子中你是正確的,但我的話是關於一個一般情況下,你可以有一個派生類與重寫的方法。 – tcb

0

這是因爲當new Glommer()被調用時沒有使用泛型Generic<Type>(),所有類型匹配都會從類中移除。

由於字符串變量是List,如果它沒有任何通用的<Type>那麼它將匹配glom(List ints)。類型檢查直到後來才完成。

當我們創建new Glommer<AnyType>時,所有類型都保留在原位,所以當我們通過我們的strings變量時,它會進行類型檢查。編譯器現在可以檢查它是否是List<Integer>,這不是它傳遞給glom(Collection<?> obj)方法。

希望這會有所幫助,如果您需要,請索取任何澄清!

+0

更改爲編譯器。 –

1

你可以閱讀更多關於Raw Types去了解它完全

基本上,原料類型,使用的遺留代碼,在原班幾乎所有的東西將成爲原料本身,在這種情況下,這些2種方法。

所以當它是生有是獲取一個List,一個用於Collection所以它稱爲方法List之一,如果它不是原始的方法是不生也,它會調用Collection之一,因爲它有額外信息