2010-11-10 17 views
7

Tanım nesnesine başvuru içeren bir nesne örnekleri sistemim var. Her miras ağacı için üst düzey bir sınıfım var. Örnek nesnesi, karşılık gelen tanım sınıfına genel bir başvuruyu içerir.Bu jenerik neden üst sınıf sınırını (Java) tanımıyor?

Geterdeki jenerikleri kullanarak, üst düzey nesnenin bir alt sınıfı, döküm yapmadan doğru tür tanımını alabilir. Ancak, soyut bir alt sınıf tekrar edemez sınıflandırma olduğunu:

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 
    } 
} 

Neden getDef bir BearDef almak için bir Bear (Animal<BearDef>) için döküm olmak gerektirir? Ayı, sonuç olarak extends Animal<? extends BearDef> olarak tanımlanmıştır. Ben Ayı sınıf çizgisini değiştirirseniz

[ Düzenleme] Hatta yabancı: (D kullanılmayan ve alakasız Bu durumda)

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

o hala çalışmıyor. D silin ve aşağıdaki satırı yukarıdaki kodda hata giderir (ama bana alt sınıf tanımları ile yapmanız gereken ne yardımcı olmuyor):

abstract class Bear extends Animal<BearDef> { } 

cevap

11

Sen ne zaman aslında ham tip Bear kullanıyorsanız o BearDef bir tür ile parametrelenmiş olmalıdır. Eğer

Bear<BlackBearDef> bear = new BlackBear(); 

veya

Bear<?> bear = new BlackBear(); 

yazdı Eğer iyi çalışır istiyorum.

başka şey: Bunu kullanmak niyetinde nasıl emin değilim ama sadece bu yerine yapıyor iyi olacağını bana muhtemel görünüyor:

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() { ... } 
} 

bu düşünme sebebim o olduğunu, getDef() yöntemi BlackBearDef olan bir Bear istiyorsa, Bear referansının Bear<BlackBearDef> olarak parametrelendirilmesi gerekir. Bu durumda (örneğiniz için de olsa), bildirilen türden bir BlackBear olduğunu bildiğinizden, bunu yalnızca BlackBear olarak atıfta bulunabilirsiniz. Açıkça, her zaman bu kadar basit değildir ve gerçek durumunuz buna izin vermeyebilir.

+2

+ 1: Beni ona yendi. – Powerlord

+0

+1 benden de. –

+0

Bu * tür bir şey anlamlıdır, ancak en azından bir BearDef olduğunu bildiğinden, ikinci satırda sahip olduğunuz şeyi esas olarak varsaymamalı mıdır? – Nicole

3

Bu da çalışacaktır:

Bear<?> bear = new BlackBear();