2010-11-10 11 views
7

Tengo un sistema de instancias de objeto que contiene una referencia a un objeto de definición. Tengo una clase de nivel superior para cada árbol de herencia. El objeto instancia tiene una referencia genérica a la clase de definición correspondiente.¿Por qué este genérico no reconoce su límite de superclase (Java)?

Utilizando genéricos en el getter, una subclase del objeto de nivel superior puede obtener el tipo correcto de definición sin conversión. Sin embargo, una subclase abstracta que es nuevo no puede subclases:

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

¿Por qué getDef requieren un Bear convertirse a (Animal<BearDef>) para obtener una BearDef? Bear se define definitivamente como extends Animal<? extends BearDef>.

[Editar ] Aún más extraño, si cambio de la línea de la clase del oso:

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

(En cuyo caso no se utiliza y D es irrelevante) que todavía no funciona. Borrar D y la siguiente línea resuelve el error en el código anterior (pero no me ayuda a hacer lo que tengo que ver con las definiciones de las subclases):

abstract class Bear extends Animal<BearDef> { } 

Respuesta

11

Usted está utilizando la materia prima de tipo Bear cuando en realidad debe parametrizarse con un tipo de BearDef. Si usted escribió

Bear<BlackBearDef> bear = new BlackBear(); 

o

Bear<?> bear = new BlackBear(); 

que trabajaría bien.

Otra cosa: No estoy seguro de cómo se va a utilizar esto, pero parece probable que mí que estaría bien haciendo esto en su lugar:

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

Mi razón para pensar esto es que si quiere un Bear cuyo método getDef() devuelve un BlackBearDef, esa referencia Bear tendría que parametrizarse como Bear<BlackBearDef>. En ese caso (para su ejemplo de todos modos), efectivamente sabe que es BlackBear del tipo declarado, por lo que también podría referirse a él como BlackBear. Dicho esto, obviamente no siempre es tan simple y tu situación real puede no permitir esto.

+2

+1: se me adelantó. – Powerlord

+0

+1 de mí también. –

+0

Ese * tipo de * tiene sentido, pero como sabe que es * al menos * un BearDef, ¿no debería asumir esencialmente lo que tienes en la segunda línea? – Nicole

3

Esto también funcionará:

Bear<?> bear = new BlackBear(); 
Cuestiones relacionadas