2

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.

brain storm
  • 30,124
  • 69
  • 225
  • 393

2 Answers2

2

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.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • `This illustrates why Java doesn't allow calling a method with the generic type parameter in it (T) if there is a ? extends wildcard`-- so what is the purpose of having it, if it cannot be called? – brain storm Feb 12 '14 at 22:49
  • You can still access elements from the pair, and have the guarantee that they're instances of Employee. Read the link you got about PECS. ? extends T allows getting information from the container. ? super T allows setting information inside the container. See [List.addAll()](http://docs.oracle.com/javase/7/docs/api/java/util/List.html#addAll%28int,%20java.util.Collection%29) for a practical example. addAll can read all the elements from the collection passed as argument, but won't modify this list. So you can use addAll() on a List and pass it a List. – JB Nizet Feb 12 '14 at 22:50
  • @user1988876 You can refer to a `Pair`, a `Pair`, or a `Pair` with the same variable. The price of that is that you can't call such methods and still preserve type safety. – rgettman Feb 12 '14 at 22:52
  • so wildcards are most useful as method parameters rather than for simple assignments such as `List extends Number> foo3 = new ArrayList();` correct? or what advantage does this assignment going to give, if I know `foo3` is going to be a `ArrayList()` – brain storm Feb 12 '14 at 23:02
  • There is no advantage to assigning an object of a class with a known type parameter to a variable with a wildcard. As you can see now, it's restrictive. It is more advantageous to provide it as a parameter to a method, so that the method is more flexible, by accepting a wider range of types. – rgettman Feb 12 '14 at 23:06
1

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.

Judge Mental
  • 5,209
  • 17
  • 22