Cosa significa il punto interrogativo nel parametro type di generics Java?


216

Questo è un piccolo frammento di codice tratto da alcuni degli esempi che accompagnano lo Stanford Parser. Sto sviluppando in Java da circa 4 anni, ma non ho mai avuto una comprensione molto forte di ciò che questo stile di codice dovrebbe indicare.

List<? extends HasWord> wordList = toke.tokenize();

Non sono preoccupato per i dettagli del codice. Ciò di cui sono confuso è ciò che esattamente l'espressione generica dovrebbe trasmettere, in inglese.

Qualcuno può spiegarmelo?


Risposte:


226
? extends HasWord

significa "Una classe / interfaccia che si estende HasWord." In altre parole, HasWordse stesso o uno dei suoi figli ... praticamente tutto ciò che avrebbe funzionato con il instanceof HasWordplus null.

In termini più tecnici, ? extends HasWordè un carattere jolly limitato, coperto nell'articolo 31 di Effective Java 3rd Edition , a partire da pagina 139. Lo stesso capitolo della 2a edizione è disponibile online in formato PDF ; la parte su caratteri jolly limitati è l'articolo 28 a partire da pagina 134.

Aggiornamento: il collegamento PDF è stato aggiornato da quando Oracle l'ha rimosso qualche tempo fa. Indica ora la copia ospitata dalla School of Electronic Engineering and Computer Science della Queen Mary University di Londra.

Aggiornamento 2: Andiamo un po 'più in dettaglio sul motivo per cui dovresti usare i caratteri jolly.

Se dichiari un metodo la cui firma prevede che tu passi List<HasWord>, l'unica cosa che puoi trasmettere è a List<HasWord>.

Tuttavia, se detta firma fosse, List<? extends HasWord>allora potresti passare un List<ChildOfHasWord>.

Si noti che esiste una sottile differenza tra List<? extends HasWord>e List<? super HasWord>. Come diceva Joshua Bloch: PECS = produttore-amplia, consumatore-super.

Ciò significa che se stai passando in una raccolta da cui il tuo metodo estrae i dati (ovvero la raccolta sta producendo elementi che il tuo metodo può usare), dovresti usare extends. Se stai passando a una raccolta a cui il tuo metodo aggiunge dati (ovvero la raccolta sta consumando elementi che il tuo metodo crea), dovrebbe usarlo super.

Questo può sembrare confuso. Tuttavia, si può vedere in List's sortdi comando (che è solo una scorciatoia per la versione a due ARG di Collections.sort). Invece di prendere un Comparator<T>, in realtà ci vuole un Comparator<? super T>. In questo caso, il comparatore utilizza gli elementi di Listper riordinare l'elenco stesso.


17
"tutto ciò che funzionerebbe con instanceof" - oltre a valori null. Ricorda che i valori null restituiscono false per qualsiasi istanza di controllo.
Eyal Schneider,

12
Non dimenticare le interfacce. Il ? non deve rappresentare una classe!
Mark Peters,

9
List<HasWord>è esattamente ciò che descrivi: un elenco che contiene oggetti xper i quali x instanceof HasWordrestituisce true e null. Non è necessario un carattere jolly per questo. Il carattere jolly significa che in realtà può essere anche un elenco di un altro tipo, purché questo tipo sia un sottotipo di HasWord. (
Ci

1
Il collegamento PDF non sembra funzionare, ma questo mi è stato utile: docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
user1338062

È strano, non ho mai ricevuto un messaggio l'anno scorso quando @ user1338062 ha pubblicato e non sapevo che il collegamento PDF non funzionava. Riparato ora. Ho anche aggiunto un link al libro stesso.
Powerlord,

65

Un punto interrogativo è un significante per "qualsiasi tipo". ?significa da solo

Qualsiasi tipo che si estende Object(incluso Object)

mentre il tuo esempio sopra significa

Qualsiasi tipo che si estende o implementa HasWord(incluso HasWordse si HasWordtratta di una classe non astratta)


2
quindi cosa public Set<Class<?>> getClasses()significa? Qual è la differenza Set<Class>? Sto guardando javax.ws.rs.core.Application.
caveau

14

List<? extends HasWord>accetta qualsiasi classe concreta che estende HasWord. Se hai le seguenti classi ...

public class A extends HasWord { .. }
public class B extends HasWord { .. }
public class C { .. }
public class D extends SomeOtherWord { .. }

... wordListpuò contenere SOLO un elenco di As o Bs o una combinazione di entrambi perché entrambe le classi estendono lo stesso genitore o null(che non riesce a verificare l'istanza di HasWorld).


8
Non solo sottoclassi concrete, ma anche astratte.
Bloparod,

2
Non solo cemento e sottoclassi astratti, ma anche sub-interfacce: List<? extends Collection<String>> list = new ArrayList<List<String>>();.
Mark Peters,

2
Non hai bisogno di caratteri jolly per questo, in realtà: List<HasWord>fa altrettanto bene per questo. Il punto qui è che questa variabile può contenere sia List<A>o List<B>che a List<HasWord>.
Paŭlo Ebermann,

12

Forse un esempio inventato del "mondo reale" sarebbe di aiuto.

Nel mio posto di lavoro abbiamo bidoni della spazzatura che hanno diversi gusti. Tutti i contenitori contengono spazzatura, ma alcuni contenitori sono specializzati e non accettano tutti i tipi di rifiuti. Quindi abbiamo Bin<CupRubbish>e Bin<RecylcableRubbish>. Il sistema di tipi deve assicurarsi che non riesca a inserire il mio HalfEatenSandwichRubbishin nessuno di questi tipi, ma può andare in un bidone della spazzatura generale Bin<Rubbish>. Se volessi parlare di uno Bindei Rubbishquali potrebbe essere specializzato, quindi non posso mettere rifiuti incompatibili, allora sarebbe Bin<? extends Rubbish>.

(Nota: ? extendsnon significa sola lettura. Ad esempio, posso, con le dovute precauzioni, estrarre un pezzo di immondizia da un bidone di specialità sconosciuta e poi rimetterlo in un posto diverso.)

Non sono sicuro di quanto aiuti. Puntatore-puntatore in presenza di polimorfismo non è del tutto evidente.


5

In inglese:

È di un Listtipo che estende la classe HasWord, inclusoHasWord

In generale, ?in generici si intende qualsiasi classe. E extends SomeClassspecifica che quell'oggetto deve estendere SomeClass(o essere quella classe).


1
In realtà, digitare invece di classe . Funziona altrettanto bene per le interfacce.
Paŭlo Ebermann,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.