2015-02-11 5 views
6

Dopo aver provato a comprendere i concetti a Spring MVC, ho trovato l'espressione Collection<? extends Book> che non ho mai visto prima. Ho cercato di capirlo da solo, ma non vedo alcuna differenza tra l'utilizzo di Collection<? extends Book> e Collection<Book>. Immagino che sia consentito solo per le estensioni del libro, ma anche per il libro. Quindi graffia quello. Ho provato a utilizzare Google, ma da allora? è un jolly in google, rende quasi impossibile la ricerca. Ho cercato lo stackoverflow per la risposta, ma tutte le domande su questo (come List<? extends MyType> e <? extends > Java syntax) presuppongono già la conoscenza di Collection<? extends T>. Ecco il codice che ha inizialmente incuriosito il mio interesse:Collezione <? extends T> vs Collezione <T>

import java.util.ArrayList; 
import java.util.Collection; 

public class Book { 
    public static void main(String[] args) { 
     BookCase bookCase1 = new BookCase(); 
     BookCase bookCase2 = new BookCase(bookCase1); 
    } 
} 

class BookCase extends ArrayList<Book> { 
    public BookCase() { 
    } 

    //acts same as public BookCase(Collection<Book> c) { 
    public BookCase(Collection<? extends Book> c) { 
     super(c); 
    } 
} 

Cosa <? extends T> fare? In cosa differisce da <T>?

EDIT:

domanda ollowup: Vuol dire che BookCase extends ArrayList<Book>BookCase estende Book?

+2

Una 'Collezione ' è una 'Collezione 'ma non una' Collezione '. – immibis

+0

Tempi come questi vorrei poter fare un segno di spunta verde con più risposte. In particolare le risposte di Makoto e Adam. Mentre tutte le risposte sono state utili, quelle in particolare mi hanno aiutato a capirlo. Quindi se stai cercando una risposta a questa domanda, ti suggerisco di leggere almeno entrambi, inclusi i commenti. Grazie a tutti!! – Evorlor

risposta

3

Si consideri il seguente

class Animal { } 
class Horse extends Animal { } 

private static void specific(List<Animal> param) { } 
private static void wildcard(List<? extends Animal> param) { } 

Senza la sintassi si estende si può usare solo la classe esatta nella firma

specific(new ArrayList<Horse>()); // <== compiler error 

Con il carattere jolly si estende è possibile consentire eventuali sottoclassi di Animal

wildcard(new ArrayList<Horse>()); // <== OK 

In genere è meglio usare il? estende la sintassi poiché rende il codice più riutilizzabile e a prova di futuro.

+1

Ma un cavallo è un animale e specifico() accetta un elenco di animali ... quindi perché non dovrebbe essere accettato un elenco di cavalli? – Evorlor

+0

Generics non funziona allo stesso modo delle firme standard dei metodi, sì foo (animale animale) potrebbe prendere qualsiasi tipo di animale. – Adam

+1

@Evorlor perché se si specifica il parametro type come Object, il compilatore vuole che sia quell'oggetto esatto –

2

Ecco l'esempio che mostra chiaramente la differenza tra Collection<? extends Book> e Collection<Book>:

public class Test { 
    public static void main(String[] args) { 
     BookCase bookCase1 = new BookCase(); 
     BookCase bookCase2 = new BookCase(bookCase1); 
     List<FictionBook> fictionBooks = new ArrayList<>(); 
     BookCase bookCase3 = new BookCase(fictionBooks); 
    } 
} 

class Book {} 
class FictionBook extends Book {} 

class BookCase extends ArrayList<Book> { 
    public BookCase() { 
    } 

    //does not act same as public BookCase(Collection<Book> c) { 
    public BookCase(Collection<? extends Book> c) { 
     super(c); 
    } 
} 

quel codice compila. Se si modifica il parametro del costruttore BookCase su Collection<Book>, questo esempio non verrà compilato.

4

Verificare this dalla documentazione.

In generale, se Foo è un sottotipo (sottoclasse o subinterface) di Bar, e G è un po 'dichiarazione di tipo generico, non è il caso che G è un sottotipo di G. Questa è probabilmente la cosa più difficile che si bisogno di conoscere i generici, perché va contro le nostre intuizioni profondamente radicate.

Dai un'occhiata anche allo next page about wildcards.

Quindi, in pratica, quando si scrive void doStuff(List<Book>){}, è possibile fare solo roba su un elenco di oggetti Book SOLO.

NonNovel s, nonMagazine s, nonComicBook s.

nuovo, questo è perché anche se Novel estende Book, G<Novel>non effettivamente estendonoG<Book>. Non è molto intuitivo, ma l'esempio nella documentazione ti aiuterà a vederlo.

3

Sia Collection<Book> e Collection<? extends Book> rappresenta una collezione che può contenere Book istanze e oggetti che possono essere considerati un Book attraverso il è-una relazione. Questa proprietà si estende anche alle interfacce.

La differenza qui è che quest'ultima forma è considerata limitata. A seconda del limite, non sarebbe possibile aggiungere o rimuovere elementi da questa raccolta.

? extends T è un upper bounded wildcard. In effetti, descrive un limite gerarchico tra un tipo (?) all'estremità inferiore e Book all'estremità superiore. E 'compreso, in modo da poter memorizzare le istanze di Book in là, ma se avete avuto altre classi e interfacce, come ad esempio:

class Novella extends Book {} 
class Magazine extends Book {} 
class ComicBook extends Book{} 
class Manga extends Magazine {} 
class Dictionary extends Book {} 
class ForeignLanguageDictionary<T extends Language> extends Dictionary {} 
interface Language {} 

... si potrebbe trovare una di queste istanze all'interno di un Collection<? extends Book>.

Ricordate che ho detto che potrebbe non essere possibile aggiungere o rimuovere elementi da questa raccolta? Ricorda questa convenzione:

Produttore esteso; consumatore super.

Si noti che questo è dal punto di vista della raccolta; se la raccolta è limitata a extends, è un produttore; se è limitato a super, è un consumatore.

Detto questo, dal punto di vista di questa raccolta, ha già prodotto tutti i suoi record, quindi non è possibile aggiungerne di nuovi.

List<? extends Book> books = new ArrayList<>(); // permanently empty 
books.add(new Book()); // illegal 

Se fosse il caso che l'avete avuto legato con ? super Book, non si poteva recuperare gli elementi da esso in un modo sano di mente - che avrebbe dovuto recuperarli come Object invece, che non è concisa.

List<? super Book> books = new ArrayList<>(); 
books.add(new Book()); 
books.add(new Manga()); 
Book book = books.get(0); // can't guarantee what Book I get back 

Soprattutto, se si sono tenuti con ? super T, è sempre e solo intenzione di inserto elementi in quella collezione.

Domanda successiva: BookCase extends ArrayList<Book> significa che BookCase extends Book?

No. Un BookCase in quel caso è un ArrayList, non un Book. Accade così che l'elenco di array sia destinato a memorizzare libri, ma è esso stesso non a Book.

+0

Quindi rappresenta il figlio minore con T, mentre significa T e solo T - nessun figlio. È corretto? – Evorlor

+0

Sta usando lo stesso è-una relazione con i bambini, quindi saresti in grado di memorizzare i bambini all'interno di 'T'. Nel mio esempio, potresti inserire un'istanza di 'Manga' all'interno di una' Collezione '. – Makoto

+0

Lasciami fare qualche ritocco qui. C'è un po 'di confusione sul posto. – Makoto

0

List<Book> è un elenco che può contenere qualsiasi libro. Poiché non vi è alcuna restrizione sul tipo di libro, è possibile aggiungere qualsiasi libro ad esso.

List<? extends Book> è anche un elenco che contiene libri, ma potrebbero esserci ulteriori restrizioni. Forse in effetti è un List<PoetryBook> e può memorizzare solo istanze di PoetryBook, puoi solo essere sicuro che ogni elemento all'interno di questo elenco è un libro. A causa di questa possibile restrizione, non è possibile aggiungere elementi a questo elenco.

Considera un metodo che prende un elenco di libri e restituisce il libro con il maggior numero di pagine.

Book getBookWithMostPages(List<? extends Book>) { 
    ... 
} 

Questo metodo può essere chiamato con List<Book> o con List<PoetryBook>.

Se si modifica la firma di

Book getBookWithMostPages(Iterable<? extends Book>) { 
    ... 
} 

allora può essere utilizzato anche con Set<ScienceBook> o tutto ciò che è iterabile e contiene libri.

+0

... ma un metodo che aggiunge un po 'di poesia a un elenco di libri: 'addSomePoetry (Elenco )' non funzionerebbe. (arrotondando la spiegazione). –

+0

Sì, questo è il punto. – phlogratos