Java Generics – How to Understand the Wildcard Type

genericsjava

I am reading the Core Java (9th edition) by Cay S. Horstmann and Gary Cornell. After making an effort, I cannot still understand the ? super Manager. Here are some materials relating to this question.

public class Pair<T> {
    private T first;
    private T second;

    public Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public void setFirst(T first) {
        this.first = first;
    }

    public void setSecond(T second) {
        this.second = second;
    }

    public T getFrist() {
        return this.first;
    }

    public T getSecond() {
        return this.second;
    }
}

The Manager inherits from Employee, and Executive inherites from Manager. Pair has methods as follows:

void setFirst(? super Manager)
? super Manager getFirst()

Since ? super Manager denotes any supertype of Manager, why I cannot call setFirst method with Employee (it is obvious that Employee is the supertype of Manager), but only with type Manager or a subtype such as Executive(but Executive is the subtype of Manager, not a supertype of Manager)?

Best Answer

One can read and re-iterate it over and over again - as it has been many times already. In a comment to your question, Philipp already linked to a question on Stackoverflow which tries to answer it. For me, the explanation of Uncle Bob did the trick.

He writes (next to a lot of other good stuff):

A List<? super Shape> is a list into which you may add Shapes. Another way to think of this is that the type <? super T> is an unknown type that T can substitute for. You may have to read that several times before you understand it. I certainly did. So here's yet another way to think about it. The type <? super T> is a type that T is derived from. It is a base class of T. Clearly if D is derived from B then you can put D instances into a List<B>. Likewise, since T derives from <? super T>, you can put T instances into a List<? super T>. Follow? No? Neither did I for awhile. It takes a bit of getting used to.

What this means in the end is that your assumption you'd be able to put super-types of Manager into your List<? super Manager> is wrong. That's not what is meant here. The super keyword solves the problem of not being able to insert stuff into generic places while you were able to get some out (with extends).

Imagine two pairs, one that extends Manager, one that "supers" it:

Pair<? extends Manager> subPair = new Pair<Manager>();
Pair<? super Manager> superPair = new Pair<Manager>();

What you can never do, is insert an Employee in any of these:

subPair.setFirst(new Employee());
superPair.setFirst(new Employee());

If you want managers, employees will never be enough. And it's worse: you can't even insert an Executive into your subPair, even though Executive extends Manager. It won't compile either:

subPair.setFirst(new Executive());

Edit: Why is that? Well, your generic subPair always refers to some "explicit" Pair, Pair<Manager> in this case. It just as well might have referred to a Pair<CoManager> (with CoManager extends Manager). Java won't know the explicit type that's actually used and thus can't allow you insertions.

But super comes to the rescue. With super you can insert Managers and their sub-types into your Pair. And that is what super is for: Inserting.

superPair.setFirst(new Executive());

Edit: Any why does that work? While extends guarantees you some type that implements (or derives from) Manager, super guarantees you any such type. So, while with extends you get a specific type with (at least) the Manager interface, with super you can insert any type with the Manager interface.

And for the bigger picture, I really suggest reading the article of Uncle Bob.

Related Topic