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.
?
as a type parameter can only be used in methods. eg:printAll(MyList<? extends Serializable>)
I cannot define classes with?
as type parameter.I understand the upper bound on
?
.printAll(MyList<? extends Serializable>)
means: "printAll
will printMyList
if it has objects that implement theSerialzable
interface."
I have a bit of an issue with thesuper
.printAll(MyList<? super MyClass>)
means: "printAll
will printMyList
if it has objects ofMyClass
or any class which extendsMyClass
(the descendants ofMyClass
)."
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:
? extends T
means any class which extendsT
. Thus, we are referring to the children ofT
. Hence,T
is the upper bound. The upper-most class in the inheritance hierarchy? super T
means any class / interface which issuper
ofT
. Thus we are referring to all the parents ofT
.T
is thus the lower bound. The lower-most class in the inheritance hierarchy
Solution 1:
?
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
- There are objects of MyClass in the list
- 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:
MyList<MyClass>
MyList<Thread>
MyList<Runnable>
MyList<ActionListener>
MyList<EventListener>
MyList<Object>
-
MyList<? super X>
whereX
isMyClass
,Thread
,Runnable
,ActionListener
,EventListener
, orObject
.
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 issuper
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".
Solution 2:
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 ofT
-
? super T
: an unknown type which is a super type ofT
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.