Understanding upper and lower bounds on ? in Java Generics

An SO User picture An SO User · Nov 5, 2013 · Viewed 25k times · Source

I am really having a tough time understanding the wild card parameter. I have a few questions regarding that.

  1. ? as a type parameter can only be used in methods. eg: printAll(MyList<? extends Serializable>) I cannot define classes with ? as type parameter.

  2. I understand the upper bound on ?. printAll(MyList<? extends Serializable>) means: "printAll will print MyList if it has objects that implement the Serialzable interface."
    I have a bit of an issue with the super. printAll(MyList<? super MyClass>) means: "printAll will print MyList if it has objects of MyClass or any class which extends MyClass (the descendants of MyClass)."

Correct me where I went wrong.

In short, only T or E or K or V or N can be used as type parameters for defining generic classes. ? can only be used in methods


Update 1:

public void printAll(MyList<? super MyClass>){
    // code code code
}

Accordint to Ivor Horton's book, MyList<? super MyClass> means that I can print MyList if it has objects of MyClass or any of the interfaces or classes it implements. That is, MyClass is a lower bound. It is the last class in the inheritance hierarchy. This means my initial assumption was wrong.

So, say if MyClass looks like:

public class MyClass extends Thread implements ActionListener{
    // whatever
}

then, printAll() will print if
1. There are objects of MyClass in the list
2. There are objects of Thread or ActionListener in the List


Update 2:

So, after having read the many answers to the question, here is my understanding:

  1. ? extends T means any class which extends T. Thus, we are referring to the children of T. Hence, T is the upper bound. The upper-most class in the inheritance hierarchy

  2. ? super T means any class / interface which is super of T. Thus we are referring to all the parents of T. T is thus the lower bound. The lower-most class in the inheritance hierarchy

Answer

Paul Bellora picture Paul Bellora · Nov 5, 2013

? as a type parameter can only be used in methods. eg: printAll(MyList<? extends Serializable>) I cannot define classes with ? as type parameter.

A wildcard (?) isn't a formal type parameter, but rather can be used as a type argument. In the example you give, ? extends Serializable is given as a type argument to the generic type MyList, of the printAll method's parameter.

Methods can also declare type parameters like classes, for example:

static <T extends Serializable> void printAll(MyList<T> myList)

I understand the upper bound on ?. printAll(MyList<? extends Serializable>) means printAll will print MyList if it has objects that implement the Serialzable interface

More accurately, it means a call to printAll will compile only if it is passed a MyList with some generic type that is or implements Serializable. In this case it would accept a MyList<Serializable>, MyList<Integer>, etc.

I have a bit of an issue with the super. printAll(MyList<? super MyClass>) means printAll will print MyList if it has objects of MyClass or any class which extends MyClass (the descendants of MyClass)

A wildcard bounded with super is a lower bound. So we could say a call to printAll will compile only if it is passed a MyList with some generic type that is MyClass or some super-type of MyClass. So in this case it would accept MyList<MyClass>, e.g. MyList<MyParentClass>, or MyList<Object>.

So, say if MyClass looks like:

public class MyClass extends Thread implements ActionListener{
    // whatever
}

then, printAll() will print if

  1. There are objects of MyClass in the list
  2. There are objects of Thread or ActionListener in the list

You're on the right track. But I think saying e.g. "it will print if there are objects of MyClass in the list" is problematic. That makes it sound like you're defining runtime behavior - generics are all about compile time checks. For example wouldn't be able to pass a MyList<MySubclass> as an argument for MyList<? super MyClass>, even though it might contain instances of MyClass, by inheritance. I would reword it to:

A call to printAll(MyList<? super MyClass>) will compile only if it is passed a:

  1. MyList<MyClass>
  2. MyList<Thread>
  3. MyList<Runnable>
  4. MyList<ActionListener>
  5. MyList<EventListener>
  6. MyList<Object>
  7. MyList<? super X> where X is MyClass, Thread, Runnable, ActionListener, EventListener, or Object.

So, after having read the many answers to the question, here is my understanding:

? extends T means any class which extends T. Thus, we are referring to the children of T. Hence, T is the upper bound. The upper-most class in the inheritance hierarchy

? super T means any class / interface which is super of T. Thus we are referring to all the parents of T. T is thus the lower bound. The lower-most class in the inheritance hierarchy

Close, but I wouldn't say "children of T" or "parents of T", since these bounds are inclusive - it would be more accurate to say "T or its subtypes", and "T or its supertypes".