20

After trying to understand the concepts at Spring MVC, I came across the expression Collection<? extends Book> which I have never seen before. I have tried to figure it out on my own, but I am seeing no difference between using Collection<? extends Book> and Collection<Book>. I was guessing that it only allowed for extensions of Book, but it does allow for Book as well. So scratch that. I have tried using Google, but since ? is a wildcard in google, it makes it nearly impossible to search for. I have searched stackoverflow for the answer, but all questions about this (such as List<? extends MyType> and <? extends > Java syntax) already assume knowledge of Collection<? extends T>. Here is the code that has initially intrigued my interest:

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

What does <? extends T> do? How does it differ from <T>?

EDIT:

Followup question: Does BookCase extends ArrayList<Book> mean that BookCase extends Book?

Community
  • 1
  • 1
Evorlor
  • 7,263
  • 17
  • 70
  • 141
  • 3
    A `Collection` is a `Collection extends Book>` but not a `Collection`. – user253751 Feb 11 '15 at 21:18
  • 1
    Times like these I wish I could green checkmark multiple answers. Specifically Makoto's and Adam's answers. While all answers were helpful, those in particular helped me understand it. So if you are looking for an answer to this question, I suggest you read both of those at the very least, including comments. Thanks everyone!! – Evorlor Feb 11 '15 at 21:53

5 Answers5

16

Consider the following

class Animal { }
class Horse extends Animal { }

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

Without the extends syntax you can only use the exact class in the signature

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

With the wildcard extends you can allow any subclasses of Animal

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

It's generally better to use the ? extends syntax as it makes your code more reusable and future-proof.

Adam
  • 35,919
  • 9
  • 100
  • 137
  • 2
    But a Horse is an animal, and specific() accepts a list of Animals...so why wouldn't a list of horses be accepted? – Evorlor Feb 11 '15 at 21:28
  • Generics doesn't work in the same way as standard method signatures, yes foo(Animal animal) could take any type of Animal. – Adam Feb 11 '15 at 21:30
  • 1
    @Evorlor because if you specify the type parameter to be some Object, the compiler wants it to be that exact object – James Wierzba Feb 11 '15 at 21:31
  • @Evorlor Perhaps [this](http://docs.oracle.com/javase/tutorial/java/generics/inheritance.html) link can be of help? – TNT Feb 11 '15 at 21:32
  • @Evorlor If `List` was a subtype of `List`, then you could have a method `addSomeCatsTo(List)`---and call it with `addSomeCatsTo(myDogList)`. The type system is here to stop you from doing that---unless your method promises to only *read* from the list. That's what you effectively say with `List extends Animal>`: you will be able to read `Animal`s from it, but won't be allowed to put any in. – Marko Topolnik Feb 11 '15 at 21:42
  • So... `Collection` can fulfill requirement of `Collection extends Animal>`. `Collection` can fulfill requirement of `Collection extends Animal>`. `Collection` can fulfill requirement of `Collection`. But `Collection` CANNOT fulfill requirement of `Collection`. Am I getting it now? – Evorlor Feb 11 '15 at 21:49
  • 1
    Yes, that is correct. `Collection` just can't stand in for `Collection` regardless of where the type variable appears, so it violates the Liskov Substitution Principle. `Collection` has a method `add(Horse)` whereas `Collection` has `add(Animal)`. Clearly, calling `add(Animal)` with any possible `Animal` must not pass through the static type checker. – Marko Topolnik Feb 11 '15 at 21:51
  • this is the best explanation of a really difficult concept I have ever seen, please makes also an example of covariance if you like – trocchietto Sep 13 '18 at 09:28
8

Both Collection<Book> and Collection<? extends Book> represents a collection that can hold Book instances and objects that can be considered to be a Book through the is-a relationship. This property extends to interfaces as well.

The difference here is that the latter form is considered to be bounded. Depending on the bound, you would not be able to add or remove elements from this collection.

? extends T is a upper bounded wildcard. In effect, it describes a hierarchical bound between some type (?) at the low end, and Book at the high end. It is inclusive, so you can store instances of Book in there, but if you had other classes and interfaces, such as:

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 {}

...you could find any of those instances inside of a Collection<? extends Book>.

Recall that I mentioned that you may not be able to add or remove things from this collection? Remember this convention:

Producer extends; consumer super.

Note that this is from the perspective of the collection; if the collection is bounded with extends, it's a producer; if it's bounded with super, it's a consumer.

That said, from this collection's perspective, it has already produced all of its records, so you cannot add new ones to it.

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

If it were the case that you had it bound with ? super Book, you could not retrieve elements from it in a sane way - you'd have to retrieve them as Object instead, which isn't concise.

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

Chiefly, if you are bound with ? super T, you only ever intend to insert elements into that collection.

Followup question: Does BookCase extends ArrayList<Book> mean that BookCase extends Book?

No. A BookCase in that instance is an ArrayList, not a Book. It so happens to be the case that the array list is bound to store books, but it itself is not a Book.

Makoto
  • 104,088
  • 27
  • 192
  • 230
  • So extends T> represents the lowest child thru T, while means T and only T - no children. Is this correct? – Evorlor Feb 11 '15 at 21:37
  • It's using the same is-a relationship with children, so you'd be able to store children inside of `T`. In my example, you could put an instance of `Manga` inside of a `Collection`. – Makoto Feb 11 '15 at 21:38
  • Let me make some tweaks here. There's a bit of confusion in place. – Makoto Feb 11 '15 at 21:40
  • So... Collection can fulfill requirement of Collection extends Book>. Collection can fulfill requirement of Collection extends Book>. Collection can fulfill requirement of Collection. But Collection CANNOT fulfill requirement of Collection. Am I getting it now? – Evorlor Feb 11 '15 at 21:45
  • I've made some tweaks to the answer. There was a bit of confusion, mostly on my part. I do apologize for that, and hopefully you'll find this answer a bit more concise. – Makoto Feb 11 '15 at 21:46
  • 1
    thank you very much for your help! I wish I could green check multiple answers, but I cannot. Know that your answer (as well as Adam's) was vital to my understanding, so thank you! I also gave you a shoutout in the comments on the question. – Evorlor Feb 11 '15 at 21:54
5

Check out this from the documentation.

In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G is a subtype of G. This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.

Take a look at the next page about wildcards too.

So basically when you write void doStuff(List<Book>){} you can only do stuff to a list of Book objects ONLY.

Not Novels, not Magazines, not ComicBooks.

Again, this is because although Novel extends Book, G<Novel> does not actually extend G<Book>. It is not very intuitive, but the example in the documentation will help you see it.

Sassa
  • 3,294
  • 2
  • 28
  • 42
2

Here's the example that clearly shows the difference between Collection<? extends Book> and 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);
    }
}

that code compiles. If you change the BookCases constructor parameter to Collection<Book>, this example won't compile.

vbezhenar
  • 11,148
  • 9
  • 49
  • 63
0

List<Book> is a list that may contain any book. Because there is no restriction on the kind of book, you can add any book to it.

List<? extends Book> is as well a list that contains books, but there might but further restrictions. Maybe in fact it is a List<PoetryBook> and it may only store instances of PoetryBook, you can only be sure that every item inside this list is a book. Because of this possible restriction you can't add any items to this list.

Consider a method that takes a list of books and returns the book with the most pages.

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

This method can be called with List<Book> or with List<PoetryBook>.

If you change the signature to

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

then it can also be used with Set<ScienceBook> or anything that is iterable and contains books.

phlogratos
  • 13,234
  • 1
  • 32
  • 37
  • ... but a method that adds some poetry to a list of books: `addSomePoetry(List extends Book>)` would not work. (just rounding off your explanation.) – Marko Topolnik Feb 11 '15 at 21:48