Generici Java (caratteri jolly)


Risposte:


123

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 .


Giusto per farlo bene, se A <B e B <C allora: <A estende C> è sbagliato?
Pablo Fernandez

Se per A <B, intendi che A estende B, allora A estende C. Tuttavia, non lo useresti nella sintassi dei caratteri jolly, diresti <? estende C> per limitare le tue scelte ad A o B.
Bill the Lizard

e in tal caso se dico <? super C> quale sarebbe la differenza?
Pablo Fernandez

3
Volevo solo consigliare un altro riferimento su Java Generics: angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
Zach Scrivena

3
@ Pablo: <? super C>significherebbe che il tuo tipo è limitato a qualcosa sopra Cnella gerarchia dei tipi. (Ci scusiamo per il ritardo nella risposta. Immagino che non abbiamo ricevuto notifiche di commenti 2 anni fa?)
Bill the Lizard,

49

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 Bdove B è un tipo. Cioè, il tipo è sconosciuto ma è possibile inserire un "limite". In questo caso, è delimitato da una classe, che è una sottoclasse di B.


Presumo che 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?
Volkan Güven

38

Josh Bloch ha anche una buona spiegazione di quando usarlo supere extendsin questo video talk di Google io dove menziona il mnemonico Producer extendsConsumersuper .

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.


Ho letto il libro di Bloch, ma non riesco ancora a vedere la differenza tra extends e super in questo caso particolare.
Pablo Fernandez

Guarda il video, penso sia abbastanza chiaro. Inoltre, penso che dovresti fare un'altra domanda su "qual è la differenza tra List <? Extends T> e List <? Super T>" dove si spera che tu possa ottenere più risposte. (se lo fai, aggiungi un collegamento da qui)
vuoto

2
Letti: perché non includere l'esempio in questa risposta per renderlo completo e autonomo. I collegamenti sono effimeri.
James Schek

3

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).


1

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

1

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 :

  1. Se questo metodo legge solo oggetti da List<A>, allora dovremmo essere autorizzati a dare List<A-sub>a questo metodo. (Perché A-sub È una A)
  2. Se questo metodo inserisce solo oggetti in List<A>, allora dovremmo essere autorizzati a dare List<A-super>a questo metodo. (Perché A è un super super)
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.