Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding upper and lower bounds on ? in Java Generics

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

like image 958
An SO User Avatar asked Nov 05 '13 18:11

An SO User


People also ask

What is upper bound and lower bound in generics Java?

The Upper Bounded Wildcards section shows that an upper bounded wildcard restricts the unknown type to be a specific type or a subtype of that type and is represented using the extends keyword. In a similar way, a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.

How do you explain upper and lower bounds?

The lower bound is the smallest value that would round up to the estimated value. The upper bound is the smallest value that would round up to the next estimated value. For example, a mass of 70 kg, rounded to the nearest 10 kg, has a lower bound of 65 kg, because 65 kg is the smallest mass that rounds to 70 kg.

How are bounds used with generics?

Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.

What is upper bounded wildcards in generics?

You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.


2 Answers

? 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".

like image 163
Paul Bellora Avatar answered Sep 20 '22 07:09

Paul Bellora


First of all T or E or K or whatever are not fixed names. They are just type variables, and you decide the name for them. T, E, K are just examples but you could call it Foo or whatever.

Now going to your first question: since the wildcard ? represents the "any and unknown" type, the unspecified one, it doesn't make any sense to declare a class generic over an unspecified type. It's useful to have wildcard in parameters of methods or in variables when you don't care about the type.

Now regarding your second question: the lower bound gives even more flexibility to your generic methods. both extends and super are the opposite:

  • ? extends T: an unknown type which is a subtype of T
  • ? super T: an unknown type which is a super type of T

The latter can be useful when you want to accept a type that is compatible with T (so that T is-a that type). A practical example can be found here.

like image 42
Jack Avatar answered Sep 21 '22 07:09

Jack