2012-01-28 51 views
1

我正在閱讀「Head First Java」 - 非常酷的書以開始使用Java。我對泛型有一個疑問。Java - 將對象多態傳遞給接受通用參數的方法

該書已經正確地表明,不可能多態地將一個子類型傳遞給接受ArrayList的方法。下面的例子 -

public class Animal { 

} 

public class Dog extends Animal { 

} 

public class Cat extends Animal { 

} 

public class AnimalTester { 
    public static void main (String[] args) { 
     new AnimalTester().go(); 
    } 


    public void go() { 
     List<Animal> animalList=new ArrayList<Animal>(); 
     List<Dog> dogList=new ArrayList<Dog>(); 
     processAnimals(animalList); // this would compile 
     processAnimals(dogList); // this would not compile 
    } 

    public void processAnimals(List<Animal> animalList) { 

    } 

} 

但是上面可以通過使用仿製藥的固定 -

public <T extends Animal> void processAnimals(List<T> animalList) { 

} 

但在上述情況下,編譯器會拋出一個異常,如果有任何試圖將添加到列表(這在書中提到)。我試過用我的IDE,它引發了一個異常。該書還提到,這是爲了確保不正確的對象(例如,貓)被添加到列表中(在我們的例子中是dogList)。

但是我能夠通過使用(T)來施放貓/狗/動物物體來實現這一點。

public <T extends Animal> void processAnimals(List<T> animalList) { 
    animalList.add(new Animal()); // compilation Error 
    animalList.add(new Dog()); // compilation Error 
    animalList.add(new Cat()); // compilation Error 
    animalList.add((T) new Cat()); // works and I can also cast it back 
            // to Cat and get a Cat object 
} 

根據本書,Java創建者拋出異常的全部原因是因爲不應該將不正確的對象添加到列表中。然而,Java允許它,因爲程序員明確地轉換它,並因此說「我知道我在做什麼」?

+3

不是一個非常具有描述性的問題標題。 – 2012-01-28 19:41:49

+0

對不起,現在試着改變它。 – 2012-01-28 19:51:27

回答

3

基本上,你在編譯器上做了一個最後的運行。

你必須考慮泛型的整個觀點。它們僅用於編譯時安全。他們沒有買別的東西。在運行時,由於類型擦除,你仍然在處理一個可以容納任何東西的List<Object>。如果你決定明確施放某些東西,那麼編譯器就不會再猜測你了。您已將編譯時的潛在危險轉移到運行時,這是您的選擇。

+0

用於說出魔法字詞的+1:「type erasure」...祝賀:) – Paul 2012-01-28 19:54:46

+0

感謝rfeak。 Java中的數組不會讓其他任何東西被添加 - 我得到一個運行時異常 - 但是ArrayList不是這樣(因爲在運行時所有東西都被當作一個對象)。爲什麼在這個特定的上下文中數組和列表行爲的方式應該有所不同? – 2012-01-28 20:01:34

+0

這將會保持向後兼容性,但是有沒有辦法讓編譯器限制這種情況發生? – 2012-01-28 20:35:36