Ho un paio di domande sui caratteri jolly generici in Java:
Qual'è la differenza tra
List<? extends T>
eList<? super T>
?Cos'è un carattere jolly limitato e cos'è un carattere jolly illimitato?
Ho un paio di domande sui caratteri jolly generici in Java:
Qual'è la differenza tra List<? extends T>
e List<? super T>
?
Cos'è un carattere jolly limitato e cos'è un carattere jolly illimitato?
Risposte:
Nella tua prima domanda, <? extends T>
e <? super T>
sono esempi di caratteri jolly limitati. Un carattere jolly illimitato assomiglia <?>
e fondamentalmente significa <? extends Object>
. Significa vagamente che il generico può essere di qualsiasi tipo. Un carattere jolly delimitato ( <? extends T>
o <? super T>
) pone una restrizione sul tipo dicendo che deve estendere un tipo specifico ( <? extends T>
è noto come limite superiore) o deve essere un antenato di un tipo specifico ( <? super T>
è noto come limite inferiore) .
I tutorial Java hanno alcune spiegazioni piuttosto buone dei generici negli articoli Caratteri jolly e Più divertimento con i caratteri jolly .
<? super C>
significherebbe che il tuo tipo è limitato a qualcosa sopra C
nella gerarchia dei tipi. (Ci scusiamo per il ritardo nella risposta. Immagino che non abbiamo ricevuto notifiche di commenti 2 anni fa?)
Se hai una gerarchia di classi A, B è una sottoclasse di A e C e D sono entrambe sottoclassi di B come sotto
class A {}
class B extends A {}
class C extends B {}
class D extends B {}
Poi
List<? extends A> la;
la = new ArrayList<B>();
la = new ArrayList<C>();
la = new ArrayList<D>();
List<? super B> lb;
lb = new ArrayList<A>(); //fine
lb = new ArrayList<C>(); //will not compile
public void someMethod(List<? extends B> lb) {
B b = lb.get(0); // is fine
lb.add(new C()); //will not compile as we do not know the type of the list, only that it is bounded above by B
}
public void otherMethod(List<? super B> lb) {
B b = lb.get(0); // will not compile as we do not know whether the list is of type B, it may be a List<A> and only contain instances of A
lb.add(new B()); // is fine, as we know that it will be a super type of A
}
Un carattere jolly delimitato è come ? extends B
dove B è un tipo. Cioè, il tipo è sconosciuto ma è possibile inserire un "limite". In questo caso, è delimitato da una classe, che è una sottoclasse di B.
List<? super B>
descriva come List accetta il tipo che è la classe genitore della classe B ? Qual è il motivo per cui C e D non compileranno hmm?
Josh Bloch ha anche una buona spiegazione di quando usarlo super
e extends
in questo video talk di Google io dove menziona il mnemonico Producer extends
Consumersuper
.
Dalle diapositive della presentazione:
Supponi di voler aggiungere metodi in blocco a
Stack<E>
void pushAll(Collection<? extends E> src);
- src è un produttore di E
void popAll(Collection<? super E> dst);
- dst è un consumatore E.
A volte potresti voler limitare i tipi di tipi che possono essere passati a un parametro di tipo. Ad esempio, un metodo che opera sui numeri potrebbe voler accettare solo istanze di Number o delle sue sottoclassi. Questo è ciò a cui servono i parametri di tipo limitato.
Collection<? extends MyObject>
significa che può accettare tutti gli oggetti che hanno una relazione IS- A con MyObject (cioè qualsiasi oggetto che è un tipo di myObject o possiamo dire qualsiasi oggetto di qualsiasi sottoclasse di MyObject) o un oggetto della classe MyObject.
Per esempio:
class MyObject {}
class YourObject extends MyObject{}
class OurObject extends MyObject{}
Poi,
Collection<? extends MyObject> myObject;
accetterà solo MyObject o figli di MyObject (cioè qualsiasi oggetto di tipo OurObject o YourObject o MyObject, ma non qualsiasi oggetto della superclasse di MyObject).
In generale,
Se una struttura contiene elementi con un tipo di modulo
? extends E
, possiamo estrarre elementi dalla struttura, ma non possiamo inserire elementi nella struttura
List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);
List<? extends Number> nums = ints;
nums.add(3.14); // compile-time error
assert ints.toString().equals("[1, 2, 3.14]");
Per inserire elementi nella struttura abbiamo bisogno di un altro tipo di carattere jolly chiamato Wildcards with super
,
List<Object> objs = Arrays.<Object>asList(2, 3.14, "four");
List<Integer> ints = Arrays.asList(5, 6);
Collections.copy(objs, ints);
assert objs.toString().equals("[5, 6, four]");
public static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (int i = 0; i < src.size(); i++) {
dst.set(i, src.get(i));
}
}
I caratteri jolly generici vengono creati per rendere più riutilizzabili i metodi che operano sulla raccolta.
Ad esempio, se un metodo ha un parametro List<A>
, possiamo dare solo List<A>
a questo metodo. È uno spreco per il funzionamento di questo metodo in alcune circostanze :
List<A>
, allora dovremmo essere autorizzati a dare List<A-sub>
a questo metodo. (Perché A-sub È una A)List<A>
, allora dovremmo essere autorizzati a dare List<A-super>
a questo metodo. (Perché A è un super super)