2010-01-14 4 views
5

Dai un'occhiata a queste tre classi. Minatchi si lascia estendere in modo che anche il tipo di ritorno dei suoi metodi possa essere esteso. Per illustrare, ho usato un metodo statico.Generics Java che estendono il tipo di metodi di restituzione

public class Minatchi<T extends Minatchi<?>>{ 

    static public <T extends Minatchi<?>> 
    List<T> listAll(){ 
     return 
     (List<T>) query(); 
    } 
} 

E così mi sottoclasse Minatchi in Lady

public class Lady 
extends Minatchi<Lady>{ 

} 

Questo è dove il comportamento discutibile avviene.

public class HelloMinatchi{ 

    private void listA(){ 
    List<Lady> uvs = Lady.listAll(); 
    for (Lady uv: uvs){ 
     logger.info(uv.getName()); 
    } 
    } 

    private void listB(){ 
    for (Lady uv: Lady.listAll()){ 
     logger.info(uv.getName()); 
    } 
    } 
} 

L'elenco di metodi A e l'elencoB sono essenzialmente uguali. listA pone l'elenco in una variabile intermedia uvs, mentre listB inserisce direttamente l'elenco All nell'intestazione del ciclo.

Tuttavia, per listB, il compilatore si lamenta Impossibile convertire Minatchi <? A Lady.

Quindi questa domanda riguarda l'integrità di progettazione dei generici Java. Ancora un'altra lamentela generica.

Si tratta di una funzionalità di progettazione intenzionale o di un bug di progettazione non intenzionale che i progettisti di generici Java non sapevano come risolvere. Se intenzionale, perché lo hanno fatto? Se bug, stanno progettando di risolverlo?

O è questo il mio problema personale che non conosco un modo migliore per dichiarare i generici? Se è così, dimmi come.

(ho usato una classe Minatchi generica perché ho metodi non statici per essere esposti a estensione di classe troppo, che ho lasciato in questione.)

+0

Ho usato una classe Minatchi generica perché ho anche metodi non statici da esporre all'estensione di classe, che ho tralasciato nel domanda. –

risposta

5

Il metodo statico non accetta la definizione del tipo generico dalla classe. ovvero il metodo listAll() non conosce lo Lady (in extends Minatchi<Lady>).

suo tipo di ritorno è dedotta dalla parte sinistra dell'espressione:

  • in listA() lato sinistro definisce che prevede List<Lady>
  • in listB() loop forEach sembra dovrebbe anche aspettarsi un Lady, ma sembra che il compilatore non sia correttamente istruito con il ciclo forEach.

Il modo per fare listB() lavoro è necessario indicare cosa tipo generico da utilizzare:

for (Lady uv : Lady.<Lady>listAll()) {..} 
+0

Grazie bozho. Cosa stavo fumando? –

1

Il tuo problema è che si lascia che il compilatore dedurre il generico argomenti al metodo listAll e nel primo caso deduce quello che vuoi perché il risultato è memorizzato in una variabile e può solo guardare il tipo di variabile. Nel secondo non si può dedurre il tipo "giusto" automaticamente, quindi è necessario specificare da soli:

for (Lady uv: Lady.<Lady>listAll()){ 
    logger.info(uv.getName()); 
} 

Si prega di notare che in questo esempio non c'è alcun motivo per la classe Minatchi ad essere generico come quello non lo fa influire sul metodo statico.

Si noti inoltre che la chiamata a Lady.listAll equivale esattamente a chiamare Minatchi.listAll (vale a dire non influisce sui tipi che il compilatore potrebbe o inferirà come argomenti generici).

+0

Signora. listAll(), non Lady.listAll ();) (corretto per te) – Bozho

+0

Se il compilatore può dedurre da una variabile, certamente non dovrebbe avere alcun problema ad inferire il tipo dalla variabile nell'intestazione del ciclo. per (Lady uv: Lady.listAll()) Questa domanda non riguarda se DOVREBBE usare una variabile intermedia. Piuttosto, si tratta del motivo per cui il progettista del linguaggio ha dimenticato di ospitare il ciclo for? Perché/non potevano usare la variabile for-loop? IOW, cosa stavano fumando? –

+0

Grazie. Avrei dovuto testare prima di postare. – sepp2k

1

Questo sta accadendo a causa della cancellazione del tipo.

Dal Java Generic tutorial

Quando un tipo generico viene creata un'istanza, il compilatore traduce quei tipi da una tecnica chiamata tipo cancellazione - un processo in cui il compilatore rimuove tutte informazioni relative ai parametri di tipo e digitare argomenti all'interno di una classe o metodo .

Poiché il Lady.ListAll chiamata viene eseguita sul tipo grezzo Minatchi, il compilatore è in grado di sapere che il tipo specifico è Minatchi

Tipo cancellazione è stato utilizzato per generici in modo che i tipi generici sarebbero compatibili con le librerie Java compilate prima che i generici fossero aggiunti alla Libreria. È stato qualche sforzo per avere reification added to Java, ma non è sulla roadmap per Java 7.

+0

davvero? Ho pensato che la cancellazione di tipo si verifica solo in fase di esecuzione. Questo errore arriva in fase di compilazione. – nanda

+0

@nanda: la cancellazione del tipo è in fase di compilazione - se il tipo era noto al runtime, non sarebbe necessario cancellarlo. –

+0

Voglio dire, sì la cancellazione è in fase di compilazione, quindi il runtime non conosce il tipo generico, ma il controllo degli errori viene prima della compilazione della classe. Come può essere compilato se ha un errore? – nanda