Suppose I have a generic class Generic<A extends BaseType>
.
Is there a notable difference, as far as the Java Language Specification is concerned, between the following two type declarations?
Generic<?>
Generic<? extends BaseType>
What about nested wildcards?
List<Generic<?>>
List<Generic<? extends BaseType>>
Thinking about this, I would assume these to be equivalent. Generic
specifies that the type parameter A
has BaseType
for an upper bound.
Thus, the wildcard should always be "automatically" or "implicitly" bounded by BaseType
, no matter whether I explicitly specify it or not.
Below, I try to reconcile my intution with the JLS.
I couldn't find information about "implicit" bounds, so I started by looking at subtyping rules.
Reading the JLS section about subtyping $4.10.2, it says:
Given a generic type declaration
C<F1,...,Fn>
(n > 0), the direct supertypes of the parameterized typeC<T1,...,Tn>
, where Ti (1 ≤ i ≤ n) is a type, are all of the following:
D<U1 θ,...,Uk θ>
, whereD<U1,...,Uk>
is a generic type which is a direct supertype of the generic typeC<T1,...,Tn>
and θ is the substitution [F1:=T1,...,Fn:=Tn].
C<S1,...,Sn>
, where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
(emphasis mine)
From what I understand, "wildcards" are not considered "types" in the JLS. So this can't apply to the first two, but it would apply to the two List
examples.
Instead, this should apply:
Given a generic type declaration
C<F1,...,Fn>
(n > 0), the direct supertypes of the parameterized typeC<R1,...,Rn>
where at least one of the Ri (1 ≤ i ≤ n) is a wildcard type argument, are the direct supertypes of the parameterized typeC<X1,...,Xn>
which is the result of applying capture conversion toC<R1,...,Rn>
(§5.1.10).
(emphasis mine)
Applying capture conversion $5.1.10 to Generic<?>
and Generic<? extends BaseType>
; I think I get the same bounds on the fresh type variables. After capture conversion, I can use the "contains" rules to establish the subtyping.
For the first example, via
If Ti is a wildcard type argument (§4.5.1) of the form ?, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).
Since A1 is BaseType
, the fresh variable has an upper bound of BaseType
.
For the second case, via
If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable whose upper bound is glb(Bi, Ui[A1:=S1,...,An:=Sn]) and whose lower bound is the null type.
glb(V1,...,Vm) is defined as V1 & ... & Vm.
I get glb(BaseType, BaseType)
, which, again, is BaseType
.
So it seems that the subtyping relationship between Generic<?>
and Generic<? extends BaseType>
goes both ways according to the JLS, which matches my intuition.
For the nested wildcards, I would use the "contains" rule:
A type argument T1 is said to contain another type argument T2, written T2 <= T1, if the set of types denoted by T2 is provably a subset of the set of types denoted by T1 under the reflexive and transitive closure of the following rules (where <: denotes subtyping (§4.10)):
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
Combined with
C<S1,...,Sn>, where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
from above, I get:
List<Generic<?>>
is a direct supertype of List<Generic<? extends BaseType>>
if Generic<?>
contains Generic<? extends BaseType>>
Although, I don't see how I use the contains rule. The only additional information I can use is subtyping, according to the rules. I already know that subtyping goes both ways between the two types.
Although, if contains with subtyping between the two were the answer, I could also show that List<String>
is a subtype of List<Object>
which it isn't and shouldn't be.
Further, I need to show something of the form Type <= OtherType
and the only rule with a right-hand-side of the form "type" is T <= T
, so these rules don't seem to help at all.
How do I get that List<Generic<?>>
and List<Generic<? extends BaseType>>
are subtypes of one another through the JLS?