2009-08-10 14 views
5

Sto avendo un problema comprensione generici Java e ho semplificata per questo esempioJava Generics circolari

class A<T extends B> { 

    public void fun(T t) { 

    } 
} 

class B { 
    A a; 

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

} 

Il problema è che questo genera un avviso perché A è definita all'interno di B ma A è già usandolo come un tipo generico.

Il mio primo istinto sarebbe che il mio progetto è sbagliato, ma in questo caso non posso cambiarlo. A è come una collezione e B è come un nodo nella collezione che gli utenti devono ignorare. Alcuni eventi possono accadere in B che richiedono riferire al genitore A.

Ma dal momento che A è definito genericamente con B, come faccio a evitare l'avviso di compilazione all'interno B.event()

Grazie

+0

L'unico avviso che riesco a vedere è l'utilizzo di A come tipo non elaborato. Se questo non è l'avvertimento a cui ti stai riferendo, per favore sii più specifico e dicci quale compilatore stai usando. – skaffman

risposta

11

Codice

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

public class B { 
    A<B> a; 

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

L'avvertimento viene sconfitto.

Motivo

variabili di tipo A devono essere dichiarate utilizzando un tipo di classe specifica, come suggerito dalla generica firma classe (A<T extends B>).

Risoluzione

Anche se questo risolve l'avviso del compilatore, il problema di fondo rimane. Laurence fornisce un'ottima spiegazione e soluzione al problema principale.

13

il problema è che si sta utilizzando un tipo crudo su questa linea:

A a; 

è necessario specificare un tipo per il parametro di tipo di a (T).

Si potrebbe fare qualcosa di simile:

A<B> a; 

ma poi una potrebbe anche non essere generico a tutti, se io sto capendo la sua dichiarazione del problema. Probabilmente si vuole fare qualcosa di simile:

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 anche questo:

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

Ci sono un paio di variazioni in-tra questi che sono forse utili. L'ultimo esempio è il più generico (ma ovviamente anche il più complicato).

Il class A<T extends B<? extends T>> è garantire che il parametro di tipo A è una B. Poiché B è generica, e ha quel parametro di tipo ciclico, si finisce per dover dire B<? extends T> (semplicemente dicendo T non funzionerà qui).

Il class B<T extends B<T>> è il più vicino possibile a emulare un "self-type" in Java. Ciò consente a B di parlare del sottotipo (quasi) concreto di se stesso. Quando sottoclassi B diresti qualcosa come "class C extends <B<C>>". Questo è utile perché ora il tipo di C.a è in realtà A<? super B<C>>.

Il bit ? super nell'ultimo esempio è utile solo se si pianifica di collegare una B con uno A che non è esattamente lo stesso tipo di B. Pensando in termini concreti, si supponga di avere uno A<Shape> e uno Circle (che si estende Shape che si estende B). Il super-jolly ti consente di usarli insieme. Senza di esso avresti bisogno di un A<Circle> anziché di un A<Shape> per il tuo Circle.

+0

Questo è corretto e un grande esempio di caratteri jolly. –