Reputation: 336
Preparing for OCPJP 6 exam (that's why I'm using Java 1.6 compiler) I've noticed something unclear to me about Java Generics. Consider the following code:
class A<K extends Number> {
public <V> V useMe1(A<? super V> a) { // OK
return null;
}
public <V> V useMe2(A<? extends V> a) { // OK
return null;
}
public <V> V useMe3(A<V> a) { // ERROR, but why, since 2 above were ok
return null;
}
}
When I try to compile the code (with 1.6 compiler), I get the error:
type parameter V is not within its bound
Despite unusability of the code above, I'm wondering why does compiler think that types <? super V>
and <? extends V>
are matching the class type bound but <V>
is not (since V is matching those both bounds).
I'm not going to modify that code, I want to understand it. The code is taken from sample OCPJP 6 exam question asking "Which line will compile?"
Upvotes: 3
Views: 1391
Reputation: 2809
The third, useMe3
, fails as V
is not guaranteed to extend Number
given the lack of bounds on its declaration <V>
. And since the argument is declared as A<V>
there is no scape, V
must extend Number
and the Java language asks the programmer to explicitly state so in this case.
That is in fact the easy one and perhaps is less obvious why the other two may work.
By using ?
in their argument type definition you are giving the chance of that bound to be compatible with extend Number
even when V
itself is a priory not restricted by any particular bound in relation to Number
.
You must notice that extend Number
is not affecting V
any longer but ?
whatever that is. Another way to put it, there is a unknown class that is represented by that ?
and must extend Number
and on top of that for method useMe1
, for instance, it must be a super of V
where V
would be determined by the code that calls that method.
This is perhaps more interesting in the case of useMe2
where V
could effectively be anything totally unrelated to Number
. Eg:
interface FooInterface { ... }
class MyNumber extends Number implements FooInterface { ... }
A<?> subject = ...;
A<MyNumber> param = ...;
FooInterface foo = subject.useMe2(param);
In the useMe2
call above, V
is FooInterface
that has nothing to do with Number
, and the ?
in in this case MyNumber
. MyNumber
is restricted by A
type-parameter bound to extends Number
and by the type-parameter definition of the argument in useMe2
to extend FooInterface
but V
itself is totally unrestricted.
Upvotes: 1