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,?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.Otherwise, no constraint is implied on Tj.
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.
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 ...
随机推荐
- Java实现浏览器端大文件分片上传
版权所有 2009-2018荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...
- C++和Python混合编程
为何人工智能(AI)首选Python?读完这篇文章你就知道了:https://blog.csdn.net/qq_41769259/article/details/79419322 C++调用Pytho ...
- vc中使用SendMessage正确发送自定义消息的方法
最近在用VC2008做开发,后来由于要用到消息的发送,而且需要自定义消息,在网上查找了很多例子,根据他们所说的,虽然大致都差不多,但是基本上没有 一个能完全做出来的.要知道VC编程有一个小地方出错,都 ...
- linux导出Excel The maximum column width for an individual cell is 255 characters
linux环境到处Excel报错: The maximum column width for an individual cell is 255 characters 解决方案: for (int i ...
- Android-系统解析AndroidManifest
在上一篇博客,Android-XML格式描述,介绍来XML在Android中的格式: Android-系统解析AndroidManifest,是分析Android系统是如何去解析AndroidMani ...
- navicat远程连接oracle
本机没有oracle,这个软件太大了. 想要远程连接oracle,本地不安装oracle的话是不行的,我们安装一个oracle instance client,然后配置navicat就ok了. 下载i ...
- sklearn 中fit_tansform 与 transform的区别
https://blog.csdn.net/anecdotegyb/article/details/74857055 先fit_transform 后transform,不然会报错.
- Git小技巧:VIM中如何填写注释信息
使用Git命令行工具的时候,经常一不小心就进入VIM界面,例如git commit没有填写任何描述信息.对于习惯了Windows可视化操作界面的用户,可能一下子会觉得无所适从,只能在键盘上一顿短按.下 ...
- C#内存释放(垃圾回收)
今天写了个很小的程序,程序的功能仅仅是截图,但是如果长时间开启并截图的时候,程序会变的很大,从刚开始的运行在任务管理器中只有十几K大小,运行一段时间后在任务管理器中看到程序可以达到1G或2G甚至更大: ...
- Oracle数据库设置Scott登录
Oracle数据库Scott登录 在安装数据库时,用户登录选项中,Scott用户默认是未解锁的. 用户名填写as sysdba:密码是原来设置的,登录进去,新建SQL窗口,输入命令: alert us ...