Why can I use super
only with wildcards and not with type parameters?
For example, in the Collection
interface, why is the toArray
method not written like this
interface Collection<T>{
<S super T> S[] toArray(S[] a);
}
Why can I use super
only with wildcards and not with type parameters?
For example, in the Collection
interface, why is the toArray
method not written like this
interface Collection<T>{
<S super T> S[] toArray(S[] a);
}
The "official" answer to your question can be found in a Sun/Oracle bug report.
Sadly, the conversation ends there. The paper to which the (now dead) link used to point is Inferred Type Instantiation for GJ. From glancing at the last page, it boils down to: If lower bounds are admitted, type inference may yield multiple solutions, none of which is principal.
As no one has provided a satisfactory answer, the correct answer seems to be "Because of the Java language deficiency".
polygenelubricants provided a good overview of bad things happening with the java array covariance, which is a terrible feature by itself. Consider the following code fragment:
This obviously wrong code compiles without resorting to any "super" construct, so array covariance should not be used as an argument.
Now, here I have a perfectly valid example of code requiring
super
in the named type parameter:Potentially supporting some nice usage:
The latter code fragment does not compile if I remove the
B
altogether, soB
is indeed needed.Note that the feature I'm trying to implement is easily obtained if I invert the order of type parameter declarations, thus changing the
super
constraint toextends
. However, this is only possible if I rewrite the method as a static one:The point is that this Java language restriction is indeed restricting some otherwise possible useful features and may require ugly workarounds. I wonder what would happen if we needed
withDefault
to be virtual.Now, to correlate with what polygenelubricants said, we use
B
here not to restrict the type of object passed asdefaultValue
(see the String used in the example), but rather to restrict the caller expectations about the object we return. As a simple rule, you useextends
with the types you demand andsuper
with the types you provide.super
to bound a named type parameter (e.g.<S super T>
) as opposed to a wildcard (e.g.<? super T>
) is ILLEGAL simply because even if it's allowed, it wouldn't do what you'd hoped it would do, because sinceObject
is the ultimatesuper
of all reference types, and everything is anObject
, in effect there is no bound.In your specific example, since any array of reference type is an
Object[]
(by Java array covariance), it can therefore be used as an argument to<S super T> S[] toArray(S[] a)
(if such bound is legal) at compile-time, and it wouldn't preventArrayStoreException
at run-time.What you're trying to propose is that given:
and given this hypothetical
super
bound ontoArray
:the compiler should only allow the following to compile:
and no other array type arguments (since
Integer
only has those 3 types assuper
). That is, you're trying to prevent this from compiling:because, by your argument,
String
is not asuper
ofInteger
. However,Object
is asuper
ofInteger
, and aString[]
is anObject[]
, so the compiler still would let the above compile, even if hypothetically you can do<S super T>
!So the following would still compile (just as the way they are right now), and
ArrayStoreException
at run-time could not be prevented by any compile-time checking using generic type bounds:Generics and arrays don't mix, and this is one of the many places where it shows.
A non-array example
Again, let's say that you have this generic method declaration:
And you have these variable declarations:
Your intention with
<T super Integer>
(if it's legal) is that it should allowadd(anInteger)
, andadd(aNumber)
, and of courseadd(anObject)
, but NOTadd(aString)
. Well,String
is anObject
, soadd(aString)
would still compile anyway.See also
Related questions
On generics typing rules:
List<Animal> animals = new ArrayList<Dog>()
?List
is different fromList<Object>
which is different from aList<?>
On using
super
andextends
:Java Generics: What is PECS?
extends
consumersuper
"super
andextends
in Java Generics<E extends Number>
and<Number>
?List<? extends Number>
data structures? (YOU CAN'T!)Suppose we have:
basic classes A > B > C and D
job wrapper classes
and one manager class with 4 different approaches to execute job on object
with usage
Any suggestions how to implement execute4 now ?
==========edited =======
Thanks to all :)
========== edited ==========
much better, any code with U inside execute2
super type U becomes named !
interesting discussion :)