2017-02-22 60 views
2

我有一個類與泛型。我知道泛型類型信息在運行時被剝離,但是這是綁定類型。我認爲在編譯java.lang.Object被替換爲綁定類型。如果我知道所有東西都至少是Animal,那麼爲什麼編譯器會將它保留爲Object?有沒有我錯過的東西會使得這項工作像我想要的?具體來說,主要方法中最後的for循環有編譯時問題。什麼是有界泛型的刪除?

謝謝!

public static void main(String[] args) throws Exception { 

    Litter<Cat> catLitter = new Litter<>(); 
    for(Cat cat : catLitter) {} 

    Litter<Animal> animalLitter = new Litter<>(); 
    for(Animal animal : animalLitter) {} 

    Litter litter = new Litter(); 
    for(Animal animal : litter) {} // Type mismatch: cannot convert from element type Object to Animal 
} 

public class Litter<T extends Animal> implements Iterable<T>{ 
    @Override public java.util.Iterator<T> iterator() { 
     return new LitterIterator(); 
    } 

    class LitterIterator implements java.util.Iterator<T> { 
     @Override public boolean hasNext() { return false; } 
     @Override public T next() { return null; } 
    } 
} 

public class Animal {} 
public class Dog extends Animal{} 
public class Cat extends Animal{} 
+3

如果你打開所有的編譯器警告,你會看到你正在使用'litter',基本上讓編譯器忽略仿製藥的存在完全是爲了這句話原始類型。 – VGR

+0

當沒有指定類型時,所有通用信息都被刪除 - 您只剩下Object了。 – Bohemian

+0

這不是那麼簡單@波希米亞。有界的類型會稍微改變規則。正如Sotirios所示,當T擴展Animal時,通常返回T的實例方法仍然會以原始類型返回Animal。我的困惑是爲什麼迭代器沒有參數化爲Animal。 – bmauter

回答

4

強制重定向:

你希望將適用於像

public class Litter<T extends Animal> implements Iterable<T>{ 
    public T get() {return null; /* or whatever */} 
    ... 
} 

012的行爲

由於Litterraw type

的類型構造函數(§8.8),實例方法的(8.4節,第9.4節),或 非靜態字段(§8.3)的原始類型C未從其 超類或超接口繼承的是對應於 對應其類型的在一般聲明擦除到C

原始類型

刪除類型變量(§4.4)是刪除其最左邊界。

然後作爲

public Animal get() {...} 

到代碼使用原始Litter類型get出現的方法。

至於Litter#iterator()然而,它的返回類型是Iterator<T>並且由於

的參數化類型的擦除(§4.5)G<T1,...,Tn>|G|

它的擦除只是Iterator。然後Iteratornext()方法被擦除到

public Object next() {...} 

所以很明顯它的返回值不能被分配給Animal類型的變量。

有什麼我失蹤,會使這項工作像我想嗎?

不與原始類型,沒有。

+0

謝謝,這個答案是非常有幫助的。我仍然在努力解決這個問題。你的第一個JLS引用會讓我認爲get()方法會返回Object,而不是你的例子中的Animal。 (我知道你是對的,有一個編譯器我雙重檢查。) 原始產仔對象的get()方法返回的動物,但它的iterator()方法返回一個原始迭代器(而不是迭代器)。這甚至是有意義的?當我在Eclipse中查看可用的方法列表時,這是令人困惑的。 – bmauter

+0

原始類型應該在Java中完全刪除,因爲它破壞了常見的代碼假設。它可能是爲了向後兼容而添加的,但在我看來這是一個錯過的決定。 – MaxZoom

+0

@bmauter對不起,我沒有看到你的評論。這是T'的'擦除(這是'Animal')和Iterator '是'Iterator'的'擦除之間的差異。然後,'Iterator'''next'也必須被刪除,因爲您正在以原始值訪問它。其類型參數'E'的刪除是'Object',因爲它是無界的。 –