Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collection<? extends T> vs Collection<T>

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?

like image 915
Evorlor Avatar asked Feb 11 '15 21:02

Evorlor


People also ask

What is the difference between List <? Super T and List <? Extends T?

super is a lower bound, and extends is an upper bound.

What is collection<? Extends?

public interface Collection<E> extends Iterable<E> The root interface in the collection hierarchy. A collection represents a group of objects, known as its elements. Some collections allow duplicate elements and others do not.

What is Extends t in Java?

The syntax for Java generics bounded wildcards, representing the unknown type by ? is: ? extends T represents an upper bounded wildcard. The unknown type represents a type that must be a subtype of T, or type T itself.

What does super t mean?

super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .


2 Answers

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.

like image 124
Adam Avatar answered Oct 23 '22 12:10

Adam


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.

like image 35
Makoto Avatar answered Oct 23 '22 13:10

Makoto