2009-08-10 21 views
5

estoy teniendo problemas para entender genéricos de Java y he simplificado para este ejemploJava Generics circulares

class A<T extends B> { 

    public void fun(T t) { 

    } 
} 

class B { 
    A a; 

    public void event() { 
     a.fun(this); 
    } 

} 

El problema es que esto genera una advertencia debido a que A se define dentro de un B pero ya está usándolo como un tipo genérico

Mi primer instinto sería que mi diseño es incorrecto, pero en este caso no puedo cambiarlo. A es como una colección y B es como un nodo en la colección que los usuarios deben anular. Ciertos sucesos pueden ocurrir en B que requieren informar a los padres A.

Pero ya que A se define genéricamente con B, ¿cómo puedo evitar la advertencia de compilación en el interior B.event()

Gracias

+0

La única advertencia que puedo ver es el uso de A como un tipo sin formato. Si esa no es la advertencia a la que se refiere, sea más específico y cuéntenos qué compilador está utilizando. – skaffman

Respuesta

11

Código

public class A<T extends B> { 
    public void fun(T t) { 
    } 
} 

public class B { 
    A<B> a; 

    public void event() { 
     a.fun(this); 
    } 
} 

es vencido la advertencia.

Razón

Las variables de tipo A deben ser declaradas usando un tipo de clase específica, según lo sugerido por la firma clase genérica (A<T extends B>).

Resolución

Aunque esto resuelve la advertencia del compilador, el problema subyacente permanece. Laurence proporciona una excelente explicación y solución al problema central.

13

el problema es que usted está utilizando un tipo de crudo en esta línea:

A a; 

es necesario especificar un tipo de parámetro de tipo de a (T).

se podría hacer algo como esto:

A<B> a; 

pero entonces A puede ser que también no es genérico para nada, si estoy entendiendo su estado de cuenta del problema. Es posible que desee hacer algo como esto:

class A<T> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
}  

o incluso esto:

class A<T extends B<? extends T>> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<? super B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
} 

Hay un par de variaciones en el medio que éstas son posiblemente útiles también. El último ejemplo es el más genérico (pero obviamente, también el más complicado).

El class A<T extends B<? extends T>> garantiza que el parámetro de tipo A es un B. Como B es genérico y tiene ese parámetro de tipo cíclico, necesita decir B<? extends T> (simplemente diciendo que T no funcionará aquí).

El class B<T extends B<T>> es lo más parecido a emular un "tipo propio" en Java. Esto permite que B hable sobre el subtipo (casi) concreto de sí mismo. Cuando subclassing B dirías algo como "class C extends <B<C>>". Esto es útil porque ahora el tipo de C.a es en realidad A<? super B<C>>.

El bit ? super en el último ejemplo solo es útil si planea conectar un B con un A que no es exactamente del mismo tipo de B. Pensando en términos concretos, suponga que tiene un A<Shape> y un Circle (que se extiende Shape que se extiende a B). El super-comodín te permite usarlos juntos. Sin él necesitaría un A<Circle> en lugar de un A<Shape> para su Circle.

+0

Esto es correcto y un gran ejemplo de comodines. –