We use the following notational conventions in this section:
-
Type expressions are represented using the letters A, F, U, V, and W. The letter A is only used to denote the type of an actual argument, and F is only used to denote the type of a formal parameter.
-
Arguments to parameterized types are represented using the letters X and Y.
-
Generic type declarations are represented using the letters G and H.
Inference begins with a set of initial constraints of the form A << F, A = F, or A >> F, where U << V indicates that type U is convertible to type V by method invocation conversion (§5.3), and U >> V indicates that type V is convertible to type U by method invocation conversion.
These constraints are then reduced to a set of simpler constraints of the forms T :>
X, T = X, or T <:
X, where T is a type parameter of the method. This reduction is achieved by the procedure given below.
Given a constraint of the form A << F, A = F, or A >> F:
If F does not involve a type parameter Tj then no constraint is implied on Tj.
e.g
public <T extends InputStream> void test1(String a) { ... }
Otherwise, F involves a type parameter Tj, and there are four cases to consider.
1. If A is the type of null
, no constraint is implied on Tj.
2. Otherwise, if the constraint has the form A << F:
3. Otherwise, if the constraint has the form A = F:
4. Otherwise, if the constraint has the form A >> F:
1、the constraint has the form A << F
If A is a primitive type, then A is converted to a reference type U via boxing conversion and this algorithm is applied recursively to the constraint U << F.
If A is Reference type ,than:
-
if F = Tj, then the constraint Tj
:>
A is implied. -
If F = U
[]
, where the type U involves Tj, then if A is an array type V[]
, or a type variable with an upper bound that is an array type V[]
, where V is a reference type, this algorithm is applied recursively to the constraint V << U.This follows from the covariant subtype relation among array types. The constraint A << F in this case means that A << U
[]
. A is therefore necessarily an array type V[]
, or a type variable whose upper bound is an array type V[]
- otherwise the relation A << U[]
could never hold true. It follows that V[]
<< U[]
. Since array subtyping is covariant, it must be the case that V << U. -
If F has the form G
<
..., Yk-1, U, Yk+1, ...>
, where U is a type expression that involves Tj, then if A has a supertype of the form G<
..., Xk-1, V, Xk+1, ...>
where V is a type expression, this algorithm is applied recursively to the constraint V = U.For simplicity, assume that G takes a single type argument. If the method invocation being examined is to be applicable, it must be the case that A is a subtype of some invocation of G. Otherwise, A << F would never be true.
In other words, A << F, where F = G
<
U>
, implies that A << G<
V>
for some V. Now, since U is a type expression (and therefore[因此,所以], U is not a wildcard type argument), it must be the case that U = V, by the non-variance of ordinary parameterized type invocations.The formulation above merely generalizes this reasoning to generics with an arbitrary number of type arguments.
-
If F has the form G
<
..., Yk-1,?
extends
U, Yk+1, ...>
, where U involves Tj, then if A has a supertype that is one of:-
G
<
..., Xk-1, V, Xk+1, ...>
, where V is a type expression. Then this algorithm is applied recursively to the constraint V << U.Again, let's keep things as simple as possible, and consider only the case where G has a single type argument.
A << F in this case means A << G
<
?
extends
U>
. As above, it must be the case that A is a subtype of some invocation of G. However, A may now be a subtype of either G<
V>
, or G<
?
extends
V>
, or G<
?
super
V>
. We examine these cases in turn. The first variation is described (generalized to multiple arguments) by the sub-bullet directly above. We therefore have A = G<
V>
<< G<
?
extends
U>
. The rules of subtyping for wildcards imply that V << U. -
G
<
..., Xk-1,?
extends
V, Xk+1, ...>
. Then this algorithm is applied recursively to the constraint V << U.Extending the analysis above, we have A = G
<
?
extends
V>
<< G<
?
extends
U>
. The rules of subtyping for wildcards again imply that V << U. -
Otherwise, no constraint is implied on Tj.
Here, we have A = G
<
?
super
V>
<< G<
?
extends
U>
. In general, we cannot conclude anything in this case. However, it is not necessarily an error. It may be that U will eventually be inferred to beObject
, in which case the call may indeed be valid. Therefore, we simply refrain[避免,节制] from placing any constraint on U.
-
-
If F has the form G
<
..., Yk-1,?
super
U, Yk+1, ...>
, where U involves Tj, then if A has a supertype that is one of:-
G
<
..., Xk-1, V, Xk+1, ...>
. Then this algorithm is applied recursively to the constraint V >> U.As usual, we consider only the case where G has a single type argument.
A << F in this case means A << G
<
?
super
U>
. As above, it must be the case that A is a subtype of some invocation of G. A may now be a subtype of either G<
V>
, or G<
?
extends
V>
, or G<
?
super
V>
. We examine these cases in turn. The first variation is described (generalized to multiple arguments) by the sub-bullet directly above. We therefore have A = G<
V>
<< G<
?
super
U>
. The rules of subtyping for wildcards imply that V >> U. -
G
<
..., Xk-1,?
super
V, Xk+1, ...>
. Then this algorithm is applied recursively to the constraint V >> U.We have A = G
<
?
super
V>
<< G<
?
super
U>
. The rules of subtyping for lower-bounded wildcards again imply that V >> U. -
Otherwise, no constraint is implied on Tj.
Here, we have A = G
<
?
extends
V>
<< G<
?
super
U>
. In general, we cannot conclude anything in this case. However, it is not necessarily an error. It may be that U will eventually be inferred to the null type, in which case the call may indeed be valid. Therefore, we simply refrain from placing any constraint on U.
-
-
Otherwise, no constraint is implied on Tj.
e.g
class A<U> { }
public class Test {
public <T extends Number> void test(
T a,
T[] b,
A<T> c,
A<? extends T> d,
A<? super T> e) {
}
public void tt(){
int a = 2;
// int[] b = new int[]{2,4};
Integer[] b = new Integer[]{1,2,3};
A<Integer> c = new A<Integer>();
A<Integer> d = new A<Integer>();
A<Integer> e = new A<Integer>();
test(a,b,c,d,e);
}
}
2、the constraint has the form A == F
-
If F = Tj, then the constraint Tj = A is implied.
-
If F = U
[]
where the type U involves Tj, then if A is an array type V[]
, or a type variable with an upper bound that is an array type V[]
, where V is a reference type, this algorithm is applied recursively to the constraint V = U.If the array types U
[]
and V[]
are the same, their component types must be the same. -
If F has the form G
<
..., Yk-1, U, Yk+1, ...>
, where U is type expression that involves Tj, then if A is of the form G<
..., Xk-1, V, Xk+1,...>
where V is a type expression, this algorithm is applied recursively to the constraint V = U. -
If F has the form G
<
..., Yk-1,?
extends
U, Yk+1, ...>
, where U involves Tj, then if A is one of:-
G
<
..., Xk-1,?
extends
V, Xk+1, ...>
. Then this algorithm is applied recursively to the constraint V = U. -
Otherwise, no constraint is implied on Tj.
-
-
If F has the form G
<
..., Yk-1,?
super
U, Yk+1 ,...>
, where U involves Tj, then if A is one of:-
G
<
..., Xk-1,?
super
V, Xk+1, ...>
. Then this algorithm is applied recursively to the constraint V = U. -
Otherwise, no constraint is implied on Tj.
-
-
Otherwise, no constraint is implied on Tj.
3、the constraint has the form A >> F
-
If F = Tj, then the constraint Tj
<:
A is implied.We do not make use of such constraints in the main body of the inference algorithm. However, they are used in §15.12.2.8.
-
If F = U
[]
, where the type U involves Tj, then if A is an array type V[]
, or a type variable with an upper bound that is an array type V[]
, where V is a reference type, this algorithm is applied recursively to the constraint V >> U. Otherwise, no constraint is implied on Tj.This follows from the covariant subtype relation among array types. The constraint A >> F in this case means that A >> U
[]
. A is therefore necessarily an array type V[]
, or a type variable whose upper bound is an array type V[]
- otherwise the relation A >> U[]
could never hold true. It follows that V[]
>> U[]
. Since array subtyping is covariant, it must be the case that V >> U. -
If F has the form G
<
..., Yk-1, U, Yk+1, ...>
, where U is a type expression that involves Tj, then:-
If A is an instance of a non-generic type, then no constraint is implied on Tj.
In this case (once again restricting the analysis to the unary case), we have the constraint A >> F = G
<
U>
. A must be a supertype of the generic type G. However, since A is not a parameterized type, it cannot depend upon the type argument U in any way. It is a supertype of G<
X>
for every X that is a valid type argument to G. No meaningful constraint on Ucan be derived from A. -
If A is an invocation of a generic type declaration H, where H is either G or superclass or superinterface of G, then:
-
If H ≠ G, then let S1, ..., Sn be the type parameters of G, and let H
<
U1, ..., Ul>
be the unique invocation of H that is a supertype of G<
S1, ..., Sn>
, and let V = H<
U1, ..., Ul>
[
Sk=U]
. Then, if V:>
F this algorithm is applied recursively to the constraint A >> V.Our goal here is to simplify the relationship between A and F. We aim to recursively invoke the algorithm on a simpler case, where the type argument is known to be an invocation of the same generic type declaration as the formal.
Let's consider the case where both H and G have only a single type argument. Since we have the constraint A = H
<
X>
>> F = G<
U>
, where H is distinct from G, it must be the case that H is some proper superclass or superinterface of G. There must be a (non-wildcard) invocation of H that is a supertype of F = G<
U>
. Call this invocation V.If we replace F by V in the constraint, we will have accomplished the goal of relating two invocations of the same generic (as it happens, H).
How do we compute V? The declaration of G must introduce a type parameter S, and there must be some (non-wildcard) invocation of H, H
<
U1>
, that is a supertype of G<
S>
. Substituting the type expression U for S will then yield a (non-wildcard) invocation of H, H<
U1>
[
S=U]
, that is a supertype of G<
U>
. For example, in the simplest instance, U1might be S, in which case we have G<
S>
<:
H<
S>
, and G<
U>
<:
H<
U>
= H<
S>
[
S=U]
= V.It may be the case that H
<
U1>
is independent of S - that is, S does not occur in U1 at all. However, the substitution described above is still valid - in this situation, V = H<
U1>
[
S=U]
= H<
U1>
. Furthermore, in this circumstance, G<
T>
<:
H<
U1>
for any T, and in particular G<
U>
<:
H<
U1>
= V.Regardless of whether U1 depends on S, we have determined the type V, the invocation of H that is a supertype of G
<
U>
. We can now invoke the algorithm recursively on the constraint H<
X>
= A >> V = H<
U1>
[
S=U]
. We will then be able to relate the type arguments of both invocations of H and extract the relevant constraints from them. -
Otherwise, if A is of the form G
<
..., Xk-1, W, Xk+1, ...>
, where W is a type expression, this algorithm is applied recursively to the constraint W = U.We have A = G
<
W>
>> F = G<
U>
for some type expression W. Since W is a type expression (and not a wildcard type argument), it must be the case that W = U, by the invariance of parameterized types. -
Otherwise, if A is of the form G
<
..., Xk-1,?
extends
W, Xk+1, ...>
, this algorithm is applied recursively to the constraint W >> U.We have A = G
<
?
extends
W>
>> F = G<
U>
for some type expression W. It must be the case that W >> U, by the subtyping rules for wildcard types. -
Otherwise, if A is of the form G
<
..., Xk-1,?
super
W, Xk+1, ...>
, this algorithm is applied recursively to the constraint W << U.We have A = G
<
?
super
W>
>> F = G<
U>
for some type expression W. It must be the case that W << U, by the subtyping rules for wildcard types.
-
-
-
If F has the form G
<
..., Yk-1,?
extends
U, Yk+1, ...>
, where U is a type expression that involves Tj, then:-
If A is an instance of a non-generic type, then no constraint is implied on Tj.
Once again restricting the analysis to the unary case, we have the constraint A >> F = G
<
?
extends
U>
. A must be a supertype of the generic type G. However, since A is not a parameterized type, it cannot depend upon U in any way. It is a supertype of the type G<
?
extends
X>
for every X such that?
extends
X is a valid type argument to G. No meaningful constraint on U can be derived from A. -
If A is an invocation of a generic type declaration H, where H is either G or superclass or superinterface of G, then:
-
If H ≠ G, then let S1, ..., Sn be the type parameters of G, and let H
<
U1, ..., Ul>
be the unique invocation of H that is a supertype of G<
S1, ..., Sn>
, and let V = H<
?
extends
U1, ...,?
extends
Ul>
[
Sk=U]
. Then this algorithm is applied recursively to the constraint A >> V.Our goal here is once more to simplify the relationship between A and F, and recursively invoke the algorithm on a simpler case, where the type argument is known to be an invocation of the same generic type as the formal.
Assume both H and G have only a single type argument. Since we have the constraint A = H
<
X>
>> F = G<
?
extends
U>
, where H is distinct from G, it must be the case that His some proper superclass or superinterface of G. There must be an invocation of H<
Y>
, such that H<
X>
>> H<
Y>
, that we can use instead of F = G<
?
extends
U>
.How do we compute H
<
Y>
? As before, note that the declaration of G must introduce a type parameter S, and there must be some (non-wildcard) invocation of H, H<
U1>
, that is a supertype of G<
S>
. However, substituting?
extends
U for S is not generally valid. To see this, assume U1 = T[]
.Instead, we produce an invocation of H, H
<
?
extends
U1>
[
S=U]
. In the simplest instance, U1 might be S, in which case we have G<
S>
<:
H<
S>
, and G<
?
extends
U>
<:
H<
?
extends
U>
= H<
?
extends
S>
[
S=U]
= V. -
Otherwise, if A is of the form G
<
..., Xk-1,?
extends
W, Xk+1, ...>
, this algorithm is applied recursively to the constraint W >> U.We have A = G
<
?
extends
W>
>> F = G<
?
extends
U>
for some type expression W. By the subtyping rules for wildcards it must be the case that W >> U. -
Otherwise, no constraint is implied on Tj.
-
-
-
If F has the form G
<
..., Yk-1,?
super
U, Yk+1, ...>
, where U is a type expression that involves Tj, then A is either:-
If A is an instance of a non-generic type, then no constraint is implied on Tj.
Restricting the analysis to the unary case, we have the constraint A >> F = G
<
?
super
U>
. A must be a supertype of the generic type G. However, since A is not a parameterized type, it cannot depend upon U in any way. It is a supertype of the type G<
?
super
X>
for every X such that?
super
X is a valid type argument to G. No meaningful constraint on Ucan be derived from A. -
If A is an invocation of a generic type declaration H, where H is either G or superclass or superinterface of G, then:
-
If H ≠ G, then let S1, ..., Sn be the type parameters of G, and let H
<
U1, ..., Ul>
be the unique invocation of H that is a supertype of G<
S1, ..., Sn>
, and let V = H<
?
super
U1, ...,?
super
Ul>
[
Sk=U]
. Then this algorithm is applied recursively to the constraint A >> V.The treatment here is analogous to the case where A = G
<
?
extends
U>
. Here our example would produce an invocation H<
?
super
U1>
[
S=U]
. -
Otherwise, if A is of the form G
<
..., Xk-1,?
super
W, ..., Xk+1, ...>
, this algorithm is applied recursively to the constraint W << U.We have A = G
<
?
super
W>
>> F = G<
?
super
U>
for some type expression W. It must be the case that W << U, by the subtyping rules for wildcard types. -
Otherwise, no constraint is implied on Tj.
-
-