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,?extendsU, 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
<?extendsU>. 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<?extendsV>, or G<?superV>. 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<?extendsU>. The rules of subtyping for wildcards imply that V << U. -
G
<..., Xk-1,?extendsV, Xk+1, ...>. Then this algorithm is applied recursively to the constraint V << U.Extending the analysis above, we have A = G
<?extendsV><< G<?extendsU>. The rules of subtyping for wildcards again imply that V << U. -
Otherwise, no constraint is implied on Tj.
Here, we have A = G
<?superV><< G<?extendsU>. 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,?superU, 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
<?superU>. 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<?extendsV>, or G<?superV>. 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<?superU>. The rules of subtyping for wildcards imply that V >> U. -
G
<..., Xk-1,?superV, Xk+1, ...>. Then this algorithm is applied recursively to the constraint V >> U.We have A = G
<?superV><< G<?superU>. 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
<?extendsV><< G<?superU>. 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,?extendsU, Yk+1, ...>, where U involves Tj, then if A is one of:-
G
<..., Xk-1,?extendsV, 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,?superU, Yk+1 ,...>, where U involves Tj, then if A is one of:-
G
<..., Xk-1,?superV, 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,?extendsW, Xk+1, ...>, this algorithm is applied recursively to the constraint W >> U.We have A = G
<?extendsW>>> 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,?superW, Xk+1, ...>, this algorithm is applied recursively to the constraint W << U.We have A = G
<?superW>>> 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,?extendsU, 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
<?extendsU>. 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<?extendsX>for every X such that?extendsX 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<?extendsU1, ...,?extendsUl>[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<?extendsU>, 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<?extendsU>.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?extendsU for S is not generally valid. To see this, assume U1 = T[].Instead, we produce an invocation of H, H
<?extendsU1>[S=U]. In the simplest instance, U1 might be S, in which case we have G<S><:H<S>, and G<?extendsU><:H<?extendsU>= H<?extendsS>[S=U]= V. -
Otherwise, if A is of the form G
<..., Xk-1,?extendsW, Xk+1, ...>, this algorithm is applied recursively to the constraint W >> U.We have A = G
<?extendsW>>> F = G<?extendsU>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,?superU, 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
<?superU>. 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<?superX>for every X such that?superX 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<?superU1, ...,?superUl>[Sk=U]. Then this algorithm is applied recursively to the constraint A >> V.The treatment here is analogous to the case where A = G
<?extendsU>. Here our example would produce an invocation H<?superU1>[S=U]. -
Otherwise, if A is of the form G
<..., Xk-1,?superW, ..., Xk+1, ...>, this algorithm is applied recursively to the constraint W << U.We have A = G
<?superW>>> F = G<?superU>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.
-
-
本文详细阐述了在类型参数约束中,如何将复杂约束简化为更简单的形式,包括T:>X, T=X, 或T <: X,其中T是方法的类型参数。通过递归算法,文章解释了不同类型表达式之间的转换过程,以及如何处理涉及泛型类型声明、数组类型和通配符类型的约束。
4万+

被折叠的 条评论
为什么被折叠?



