javac之Inferring Type Arguments Based on Actual Arguments
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.
Type parameters are represented using the letters S and T
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.Otherwise, no constraint is implied on Tj.
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.
javac之Inferring Type Arguments Based on Actual Arguments的更多相关文章
- [GraphQL] Filter Data Based on Query Arguments with GraphQL
With GraphQL, every field and nested object can have a set of arguments which can be used to request ...
- ERROR: HHH000091: Expected type: java.sql.Timestamp, actual value: java.lang.Integer
在将MySql的数据对应到Java的实体类的时候, 遇到了错误 关键点: Hibernate从mysql数据库查出来的Timestamp类型的数据, 会被Hibernate(或者是数据库连接池Drui ...
- Run Configurations(Debug Configurations)->Arguments里填写program arguments和VM arguments
如图: 1.program arguments存储在String[] args里 2.VM arguments设置的是虚拟机的属性,是传给java虚拟机的.KV形式存储的,是可以通过System.ge ...
- Javac之关于方法的调用1
方法的调用从Attr类的visitApply()方法进入,如下: /** Visitor method for method invocations. * NOTE: The method part ...
- Javac之关于方法的选择
15.12. Method Invocation Expressions 15.12.1. Compile-Time Step 1: Determine Class or Interface to S ...
- javac之Method Invocation Expressions
15.12.1. Compile-Time Step 1: Determine Class or Interface to Search 15.12.2. Compile-Time Step 2: D ...
- 阅读The Java® Language Specification需要知道的术语
Null Pointer Exception,简称NPE 在java中,static final修饰的是常量.根据编译器的不同行为,常量又可分为编译时常量和运行时常量. 举例说明吧 public st ...
- parameters arguments 形式参数 实际参数
parameter和argument的区别 – 笑遍世界 http://smilejay.com/2011/11/parameter_argument/ https://en.wikipedia.or ...
- Spock - Document -04- Interaction Based Testing
Interaction Based Testing Peter Niederwieser, The Spock Framework TeamVersion 1.1 Interaction-based ...
随机推荐
- 在 JNI 编程中避免内存泄漏与崩溃
JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互——在 Java 程序中 ...
- js 面向对象 定义对象
js面向对象看了很多,却没有完全真正的理解,总是停留在一定的阶段,这次再认真看一下. 面向对象包含两种:定义类或对象:继承机制:都是通过工厂模式,构造函数,原型链,混合方法这四个阶段,原理也一样,只是 ...
- Hibernate的查询方式汇总
分别是HQL查询,对象化查询Criteria方法,动态查询DetachedCriteria,例子查询,sql查询,命名查询. 如果单纯的使用hibernate查询数据库只需要懂其中的一项就可以完成想要 ...
- [LeetCode] Unique Paths && Unique Paths II && Minimum Path Sum (动态规划之 Matrix DP )
Unique Paths https://oj.leetcode.com/problems/unique-paths/ A robot is located at the top-left corne ...
- Linq to Object 的简单使用示例
语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,可为 C# 和 Visual Basic 语言语法提供强大的查询功能. LINQ 引入了标准易学的数据查询和更新 ...
- JS代码指导原则
一.什么是平稳退化? 如果含有JS代码的网页在用户浏览器不支持JS(或者禁用JS)时,用户仍然能够顺利浏览(网站功能正常,只是视觉效果可能差一些),那么这个网页就能够平稳退化 网页能够平稳退化是很必要 ...
- ABP框架中微服务跨域调用其它服务接口
AjaxResponse为ABP自动包装的JSON格式 /// <summary> /// 通过地址和参数取得返回OutPut数据 /// </summary> /// < ...
- C#存储过程调用的三个方法
//带参数的SQL语句 private void sql_param() { SqlConnection conn = new SqlConnection("server=WIN-OUD59 ...
- .Net core,EFCore 入门
我在百度上搜了一下.net core和efcore 入门案例.好多博客都是大概说了一下做法,对于小白而言还是一头雾水,我今天就抽出一点时间,写一个详细的入门小案例,就一张表没有什么业务可言.主要是操 ...
- .net core AOP之Filter
当我们进行项目开发时,往往在开发过程中需要临时加入一些常用功能性代码,如身份验证.日志记录.异常获取等功能.如果每个方法中都加入这些功能性代码的话,无疑使项目显得过于臃肿,代码繁杂.这时候就要加入过滤 ...