Question

I am reading Core Java volume-1 by Horstmann, Cay.S on generics. I am not able to understand some explanation of the text book. I give the sample code below which the author refers to. followed by the text from the book and my question.

 class Employees{ }

class Manager extends Employees { }

class Pair<T>{

    private T first;
    private T second;

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


    void setFirst(T value){
        first=value;
    }

    T getFirst(){
        return first;
    }

}


public class WildCardGenerics {

    public static void main(String[] args){


        Manager ceo = new Manager();
        Manager cfo=new Manager();

        Employees clerk = new Employees();

        Pair<Manager> managers= new Pair<>(ceo,cfo);
        Pair<? extends Employees> employees=managers;

        employees.setFirst(clerk);



    }
    }

From the book:

"""No corruption is possible. The call to setFirst is a type error. To see why, let us have a closer look at the type Pair<? extends Employee>. Its methods look like this:

? extends Employee getFirst()
void setFirst(? extends Employee)

This makes it impossible to call the setFirst method. The compiler only knows that it needs some subtype of Employees, but it doesn't know which type. It refuses to pass any specific type - after all ?might not match it."""

Question: I do not understand why it refuses to pass any specific type. so what does this method accept? ? extends Employee -- means include Employee and any subtype of Employee. so passing an Employee should be legal correct?

From the book:

pair<? super Manager> has methods:
void setFirst(? super Manager)
? super Manager getFirst()

The compiler doesnt' know the exact type of the setFirst method and therefore can't call it with an object of type Employee or Object, but only with Manager or a subtype such as executive.

Question: So here I say the method can accept any Manager objects or that extends Manager object (similar to subytpe bound above). Not clear to me as why?

From the book:

Intuitively speaking, wildcards with supertype bounds let you write to a generic object, while wildcards with subtype bounds let you read from a generic object.

Question: I cannot follow it at all. It sounds simple,but not following the logic as what is meant.

Was it helpful?

Solution

The following assignment is legal, provided Clerk is an Employees [sic].

Pair<? extends Employees> employees = new Pair<Clerk>(clerk1, clerk2);

You shouldn't be able to call setFirst and pass a Manager, because here, it's really Pair<Clerk>.

This illustrates why Java doesn't allow calling a method with the generic type parameter in it (T) if there is a ? extends wildcard. The compiler doesn't know which class it really is - Employee? A subclass? Which subclass? Due to type erasure, the JVM can't check for type safety, so the compiler must disallow all such calls with everything except null, which can be cast to any reference type and is always allowed.

With ? super Employee, the lower bound is Employee. It could be Pair<Object>. But, passing an Employee or one of its subclasses is safe, because they are subclasses of anything allowed by ? super Employee.

OTHER TIPS

Always read ? extends T as "some CAP#1 extending T", and ? super T as "some CAP#2 that T extends".

Now your examples are more readable:

"No corruption is possible. The call to setFirst is a type error. To see why, let us have a closer look at the type Pair< some CAP#1 extending Employee >. Its methods look like this:

CAP#1 getFirst()
void setFirst( CAP#1 value )

Since CAP#1 is a made-up type, you can't call setFirst() with an Employee, because you can't know if CAP#1 is Employee or some random subtype of it. setFirst() is a contravariant method; it consumes instances of the generic type.

However, no matter what CAP#1 is, it extends Employee, so you can call getFirst() and assign the result to an Employee-typed variable. getFirst() is covariant; it produces instances of the generic type.

So you ask, why on earth would you ever want a variable of type Pair< ? extends Employee >, if you can't use half the methods on such a variable?

Because the one thing you can do with wildcard types is get around some of the variance issues in Java. Whether I have a Pair< Employee > or a Pair< Manager > or a Pair< SomeClassExtendingManager >, I can assign that thing to a variable of type Pair< ? extends Employee >. I cannot assign a Pair< Manager > to a variable of type Pair< Employee >, even if Pair has no contravariant methods in it, because the type system can't figure that out.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top