2016-01-25 14 views
8

Sto cercando di imparare Java Generics jolly leggendo la seguente: http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103Le differenze tra `copia (Lista <? super T> dest, Lista <? extends T> src)` e `copia (Lista <T> dest, Lista <? extends T> src)`

Ci è un esempio nel materiale:

public class Collections { 
    public static <T> void copy (List<? super T> dest, List<? extends T> src) { 
     for (int i=0; i<src.size(); i++) 
     dest.set(i,src.get(i)); 
    } 
} 

mi chiedevo se posso cambiare la firma del metodo come segue:

public static <T> void copy(List<? super T> dest, List<? extends T> src) { 

public static <T> void copy(List<T> dest, List<? extends T> src) { 

Ci sono differenze tra questi due sinatures metodo?

Esempi sarebbero apprezzati.

+2

Trovato una grande spiegazione qui: http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java/4343547 # 4343547 –

+0

@DzmitryPaulenka Grazie per il vostro aiuto, ma non sono ancora sicuro delle differenze tra 'Elenco ' e 'Elenco ' in questo caso.Penso che 'Lista ' funzioni come 'Elenco '. – Xin

risposta

5

Sei corretto. In questo caso, gli Argomenti tipo dei due parametri vengono utilizzati per esprimere la relazione che dest deve contenere oggetti di un tipo super degli oggetti in src. Quindi se dici src contiene <? extends T> allora è sufficiente dire che dest contiene oggetti di T.

Si può anche esprimere il contrario, vale a dire:

List<? super T> dest, List<T> src 

nello stesso senso.

EDIT: ho il sospetto che l'autore di rafforzare il punto sul PECS principle

+1

Non solo per "simmetria", ma anche per annullare il [principio PECS] (http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs) (Non mi piace la descrizione di questo La cosa "PECS", come nella sua forma breve, è semplicemente ambigua e forse fuorviante, ma con una descrizione dettagliata, il punto chiave dovrebbe essere chiaro) – Marco13

+0

Buon punto: lo modificherò. –

4

Come matt freake pointed out in his answer, non c'è molta differenza pratica tra

public static <T> void copyA(List<? super T> dest, List<? extends T> src) // and 
public static <T> void copyB(List<  T> dest, List<? extends T> src) 

Il frammento di seguito contiene un exampleShowingThatTheyAreBasicallyEquivalent.

Il motivo per cui gli autori hanno scelto di utilizzare ? super T è molto probabile che volessero enfatizzare lo PECS principle: Producer extends - Consumer super.

In questo esempio, il primo elenco è un utente di oggetti. Riceve solo oggetti dall'altra lista. Pertanto, il suo tipo dovrebbe essere List<? super T>.

Tuttavia, il frammento di seguito contiene anche un exampleShowingOneSubtleDifference .Io non può certo pensare di un caso in cui questo è davvero praticamente rilevanti, ma solo per farlo notare: Quando si aggirare l'inferenza di tipo, e il PIN del tipo <T> a un particolare tipo, è ancora possibile passare in un List<? super T> come primo argomento del primo metodo. Nella seconda, il tipo deve corrispondere esattamente - ma questo è semplicemente quello che dice la firma del metodo, quindi forse è ovvio ...

import java.util.List; 

public class PecsExample 
{ 
    public static void exampleShowingOneSubtleDifference() 
    { 
     List<? super Number> superNumbers = null; 
     List<Number> numbers = null; 

     PecsExample.<Number>copyA(superNumbers, numbers); // Works 
     //PecsExample.<Number>copyB(superNumbers, numbers); // Does not work 
    } 

    public static void exampleShowingThatTheyAreBasicallyEquivalent() 
    { 
     List<? super Object> superObjects = null; 
     List<? super Number> superNumbers = null; 
     List<? super Integer> superIntegers = null; 

     List<Object> objects = null; 
     List<Number> numbers = null; 
     List<Integer> integers = null; 

     List<? extends Object> extendsObjects = null; 
     List<? extends Number> extendsNumbers = null; 
     List<? extends Integer> extendsIntegers = null; 

     copyA(objects, objects); 
     copyA(objects, numbers); 
     copyA(objects, integers); 
     copyA(numbers, numbers); 
     copyA(numbers, integers); 
     copyA(integers, integers); 

     copyA(superObjects, objects); 
     copyA(superObjects, numbers); 
     copyA(superObjects, integers); 
     copyA(superNumbers, numbers); 
     copyA(superNumbers, integers); 
     copyA(superIntegers, integers); 

     copyA(objects, extendsObjects); 
     copyA(objects, extendsNumbers); 
     copyA(objects, extendsIntegers); 
     copyA(numbers, extendsNumbers); 
     copyA(numbers, extendsIntegers); 
     copyA(integers, extendsIntegers); 

     copyB(objects, objects); 
     copyB(objects, numbers); 
     copyB(objects, integers); 
     copyB(numbers, numbers); 
     copyB(numbers, integers); 
     copyB(integers, integers); 

     copyB(superObjects, objects); 
     copyB(superObjects, numbers); 
     copyB(superObjects, integers); 
     copyB(superNumbers, numbers); 
     copyB(superNumbers, integers); 
     copyB(superIntegers, integers); 

     copyB(objects, extendsObjects); 
     copyB(objects, extendsNumbers); 
     copyB(objects, extendsIntegers); 
     copyB(numbers, extendsNumbers); 
     copyB(numbers, extendsIntegers); 
     copyB(integers, extendsIntegers); 
    } 

    public static <T> void copyA(List<? super T> dest, List<? extends T> src) 
    { 
     for (int i = 0; i < src.size(); i++) 
     { 
      dest.set(i, src.get(i)); 
     } 
    } 

    public static <T> void copyB(List<T> dest, List<? extends T> src) 
    { 
     for (int i = 0; i < src.size(); i++) 
     { 
      dest.set(i, src.get(i)); 
     } 
    } 
} 
+0

Grazie per gli esempi. Sono molto utili. – Xin