Reputation: 177
I'm trying to figure out why I can't I use super
in a generic method declaration? See the example below, it doesn't compile, but I'm not sure why.
public class A<E> {
public <T extends A> void test1(T t) { // Compiles fine
}
public <T super A> void test2(T t) { // Compilation error??
}
public <T super A> <T> void test3(T t) { // Compilation error??
}
}
class A {}
....
Upvotes: 0
Views: 170
Reputation: 78579
There is a difference between type parameters and type arguments. The use of wildcards (super
and extends
) is for type arguments, that is, you declare them at the call site when you're actually defining the corresponding value of a type parameter. Alternatively, the keyword extends
can be used for type parameter constraints.
As such, in the definition class List<T>{}
, T
is called a type parameter. Whe you a declare a reference of type List
, at the call site you are allowed to provide a type argument for T
, which can be an invariant (i.e. List<String> jedis
) or a wildcard with super or with extends (i.e. List<? extends Number> myNums
, List<? super String> names
).
The keyword extends
can also be used in a totally different purpose to declare constraints for a given type parameter. For instance, the declaration:
class List<T extends CharSequence>{}
The type parameter T
is constrained. This would imply that whenever you declare a type argument for your type parameter T
, it must be of type CharSequence
or any of its subtypes.
As such List<String>
would be valid declaration, but List<Integer>
would not.
The use of the keyword super
is not allowed in the declaration of type parameter constraints, probably because it does not make a lot of sense, in your declaration, what could be a valid type argument for T
that is not A
itself?
Upvotes: 2
Reputation: 122429
Think about it, if a method could have the signature
public <T super A> void test2(T t) {
}
then it could take any object as argument. Why? Because, for example, you can always infer T
as Object
(Object
is a supertype of A
), and any object is an instance of Object
, so it works. So declaring it this way would be pretty redundant. You could just write
public void test2(Object t) {
}
for the same effect.
Upvotes: 2