2015-08-25 97 views
-2

我嘗試將類型爲SubTest的對象添加到具有通用類型T的列表中,該列表被定義爲<T extends SubTest>。我期望這個工作,但編譯器告訴我,它不能將SubTest轉換爲T。我只是在這裏看不到問題。Java泛型:編譯器將不會推斷類型,儘管它們兼容

下面是完整的代碼:

public class Test<T extends Test.SubTest> { 

    private List<T> list = new ArrayList<T>(); 

    public void add() { 
     list.add(new SubTest()); //<- compile error here 
    } 

    protected static class SubTest { 
    } 

} 

是的,我知道我可以簡單的寫

list.add((T) new SubTest()); 

,它會工作。但問題是:爲什麼不工作 沒有不必要的轉換?

+2

這裏的根本問題是'T'可能是'SubTest'的_subtype_,在這種情況下,將'SubTest'添加到'list'會主動地破壞類型安全。演員陣容不僅僅是必要的,在合理的情況下很可能會失敗。 –

回答

3

類型參數T可能是SubTest,但它也可以是任何潛在的子類SubTest。如果T是這樣一個子類,那麼你不能add a SubTestlist,因爲它是一個超類。

因爲編譯器不知道哪一個類T確實是,它不能讓你通過一個SubTestadd;它可能違反類型安全性,Java泛型可幫助您維護。

轉換到T將允許您編譯它,因爲可能有效的轉換告訴編譯器,「我知道我在做什麼,這會起作用」。但是,這可能會導致類型安全違規,如上所述。這可能在運行時表現爲ClassCastException,例如「不能投SubSubTest到SubTest」(如果TSubSubTestSubTest的子類)。

+0

是的,你絕對正確!謝謝。只是沒有看到它。我想我應該停止今天的編碼,而不是一些睡眠;) – Entrusc

+0

我試圖理解這一點。所以'List '預計是一個同質集合,列表中的所有元素都是相同類型的?但是,如果聲明'List list',則add()可以自由地添加擴展'SubTest'的一個類的任何對象(包括一個'SubTest'對象本身)。在這種情況下,編譯器確信所有元素都是相同類型的(即'SubTest')。 –

0

因爲SubTest超類T。當您聲明變量lList<T>時,您明確指出l的內容至少爲T,並且任何客戶端代碼都應該能夠執行列表中任何項目上由T公開的所有操作。由於T可能比SubTest更具體,因此不能將SubTest實例添加到l,因爲此實例不一定遵從T的合同。