2010-11-10 59 views
7

我有一個包含對定義對象的引用的對象實例系統。我爲每個繼承樹都有一個頂級類。實例對象具有對相應定義類的通用引用。爲什麼不能識別它的超類邊界(Java)?

在getter中使用泛型,頂級對象的子類可以在不投射的情況下獲得正確類型的定義。然而,一個抽象類,再次子類不能:

class Def { } 

abstract class Animal<D extends Def> { 
    D def; 
    D getDef() { return def; } 
} 

class CatDef extends Def { } 
class Cat extends Animal<CatDef> { } 

abstract class BearDef extends Def { } 
abstract class Bear<D extends BearDef> extends Animal<D> { } 

class BlackBearDef extends BearDef { } 
class BlackBear extends Bear<BlackBearDef> { } 

class AnimalDefTest { 
    public static void main (String... args) { 
     Cat cat = new Cat(); 
     CatDef catDef = cat.getDef(); // CatDef works fine 

     Bear bear = new BlackBear(); 
     BearDef bearDef = bear.getDef(); // Error: Expected Def not BearDef? Why??? 
     BearDef bearDef2 = ((Animal<BearDef>)bear).getDef(); // Works 
    } 
} 

爲什麼getDef需要Bear強制轉換爲(Animal<BearDef>)得到一個BearDef?熊最終定義爲extends Animal<? extends BearDef>

[編輯]更奇怪的是,如果我改變了熊類線:

abstract class Bear<D extends BearDef> extends Animal<BearDef> { } 

(在這種情況下,d是未使用的,是不相關的),它仍然不起作用。刪除d及以下線路解決了上面的代碼中的錯誤(但不會幫我做什麼,我需要與子類的定義做):

abstract class Bear extends Animal<BearDef> { } 

回答

11

您使用的是原始類型Bear事實上,當應使用BearDef類型進行參數化。如果你寫

Bear<BlackBearDef> bear = new BlackBear(); 

Bear<?> bear = new BlackBear(); 

它會正常工作。

另一件事:我不知道你打算如何使用這一點,但它似乎有可能我說,你會被罰款只是在做這個:

abstract class Bear extends Animal<BearDef> {} 

class BlackBear extends Bear { 
    // make use of covariant return type to make BlackBear return correct def 
    @Override 
    BlackBearDef getDef() { ... } 
} 

我的思考這個原因是如果您想要BeargetDef()方法返回BlackBearDef,該Bear參考需要參數化爲Bear<BlackBearDef>。在這種情況下(無論如何),您實際上知道它是來自聲明類型的BlackBear,所以您可能只是將其稱爲BlackBear。也就是說,這顯然不總是那麼簡單,你的實際情況可能不會允許這樣做。

+2

+1:打我給它。 – Powerlord 2010-11-10 16:58:32

+0

也是我+1。 – 2010-11-10 17:01:18

+0

* *有點合理,但是因爲它知道它至少是一個BearDef,它不應該假設你在第二行有什麼? – Nicole 2010-11-10 17:01:50

3

這將工作太:

Bear<?> bear = new BlackBear(); 
相關問題