2015-07-04 15 views
5

Il problema è in una restrizione generica:È possibile implementare il metodo con la lista di firme <Classe <? estende Annotation >> in Java?

public List<Class<? extends Annotation>> getAnnotations() { 
    return new ArrayList<>(Arrays.asList(Override.class)); 
} 

tipo reale di ritorno è ArrayList<Class<Override>>
metodo si aspetta List<Class<? extends Annotation>>

Class<Override> è un sottotipo di Class<? extends Annotation>
Class<? extends Annotation> c = Override.class; // permesso

ArrayList è un sottotipo di List, se i tipi di elementi corrispondono:
List<? extends Number> l = new ArrayList<Integer>(); // ammessi

Tuttavia, questo non è consentito:

List<Class<? extends Annotation>> l = Arrays.asList(Override.class); 
List<Class<? extends Annotation>> l = new ArrayList<>(Arrays.asList(Override.class)); 

E 'anche possibile o Class jolly sono rotti?

+0

@kocko cosa hai usato java? Ho jdk1.7_079, ecco uno screenshot https://www.dropbox.com/s/p6gybp1jct19ehg/generics.jpg – AdamSkywalker

+1

Ho giocato un po 'con questo e penso di aver trovato il motivo. Scriverò una risposta dopo un po '. –

+1

Da testing, come in Java 7 è necessario parametrizzare la chiamata statica 'Array. > asList (Override.class); '. Con Java 8 non ho bisogno di –

risposta

2

Suppongo che ciò sia dovuto alla natura di inferenza del tipo jdk 1.7.

Come forse già sapete, il metodo Arrays.asList(T ... elems) è generico, ma raramente specificare esplicitamente il tipo-parametro che vorremmo il metodo con cui lavorare e quindi abbiamo affidamento la funzione inferenza di tipo del compilatore.

Così, quando il compilatore vede un Arrays.asList(Override.class) dichiarazione sarà dedurre che il tipo di parametro per il metodo dovrebbe essere sostituito con Class<Override>, vale a dire che avremmo un versione del metodo in questa forma:

public List<Class<Override>> asList(Class<Override> ... elems) 

Tuttavia, se si esplicitamente impostato il parametro di tipo per il metodo di

List<Class<? extends Annotation>> l = 
       Arrays.<Class<? extends Annotation>>asList(Override.class); 

poi il compilatore sarà effettivamente sapere qual è il tipo di parametro deve essere sostituita con e poi il versione del metodo .asList() sarebbe:

public List<? extends Annotation> asList(Class<? extends Annotation> ... elems) 

Ora questo compilerà bene, dal momento che Class<? extends Annotation> è compatibile a Class<Override>. In Java8, la funzione di inferenza del tipo è ulteriormente migliorata, quindi non è necessario impostare in modo esplicito il parametro type per il metodo .asList().

Tuttavia, il più domanda interessante va a

Perché List<Class<Override>> non è compatibile con List<Class<? extends Annotation>>?

Il java.lang.Class è un final uno, che aiuterebbe a rispondere alle seguenti due domande, la cui combinazione risponderà alla domanda di cui sopra.:)

Quindi,

  • Che cosa un List<Class<Override>> significa?

List<Class<Override>> significa che è possibile aggiungere solo istanze di Class<Override> e nient'altro all'elenco. Il che è fantastico, sapendo che non possiamo nemmeno aggiungere sottoclassi Class<Override>, dal momento che il tipo Class è final.

  • Che cosa significa "List<Class<? extends Annotation>>"?

Questo tipo di List rappresenta un'intera famiglia di liste di classi, che sono tutti sottoclassi di tipo Annotation, il che significa che possiamo aggiungere con successo qualsiasi tipo di annotazione (per esempio, SuppressWarnings.class, Override.class, Documented.class , ecc.) alla lista.

lascia supporre che il seguente esempio è stato effettivamente corretto:

List<Class<Override>> overrides = Arrays.asList(Override.class); 
List<Class<? extends Annotation>> annotations = new ArrayList<>(); 
annotations = overrides; 
annotations.add(SuppressWarnings.class); //HUGE PROBLEM 
annotations.add(Documented.class); //ANOTHER HUGE PROBLEM 

Le due enormi problemi derivano dal fatto che stiamo cercando di aggiungere un po 'non Override casi al overrides, che è molto sbagliato.

Abbiamo un compilatore abbastanza intelligente che può effettivamente rilevare tali possibili problemi e lanciare un errore in fase di compilazione è il modo per impedirci di farlo.

Maggiori informazioni:

+0

grazie per il tempo speso. la prima parte dice che siamo stati ingannati con il rilevamento del tipo. per quanto ne so, c'è un cambiamento in Java8, che analizza parte sinistra dell'istruzione assign, quindi risolve questo problema. la seconda parte si riferisce ad un classico problema di sottotitoli nelle collezioni, mi è familiare. Aspettiamo qualche giorno per vedere se abbiamo perso qualcosa qui, e se tutto è OK, lo accetterò. grazie ancora :) – AdamSkywalker

+0

Prego. :) –

1

ArrayList è un sottotipo di una lista, se i tipi di elementi corrispondono:

List<? extends Number> l = new ArrayList<Integer>(); // allowed 

Sì, ma nel tuo esempio i tipi di elementi non corrispondono:

List<Class<? extends Annotation>> l = new ArrayList<Class<Override>>(); 

Certo, Class<Override> è un sottotipo di Class<? extends Annotation>, ma proprio come List<String> non è un sottotipo di List<Object>, List<Class<Override>> non è un sottotipo di List<Class<? extends Annotation>>. Sarebbe un sottotipo di List<? extends Class<? extends Annotation>>, però.

Detto questo, la ragione per cui il codice non viene compilato è che in Java 7, l'inferenza di tipo non prende in considerazione il tipo di ritorno del metodo quando inferisce il tipo di un'espressione di dichiarazione di ritorno, quindi imposta il tipo più specifico che potrebbe essere assegnato a

Arrays.asList(Override.class) 

non rendendosi conto che l'istruzione return avrebbe compilato solo con un tipo più flessibile (Java 8 inferenza dei tipi è più intelligente, btw).Una soluzione consiste nello specificare esplicitamente il tipo di argomento:

Arrays.<Class<? extends Annotation>(Override.class); 

o dare l'inferenza dei tipi di Java 7 un suggerimento assegnando a una variabile locale prima:

List<Class<? extends Annotation>> list = Arrays.asList(Override.class); 
return list; 

o modificare il tipo di metodo di ritorno a

List<? extends Class<? extends Annotation>> getAnnotations() 

quindi il tipo dedotto non ha importanza.

+0

l'ultima riga del codice sembra ridicola, ma funziona, lol – AdamSkywalker

Problemi correlati