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 ...
随机推荐
- PHP数据库抽象层--PDO(PHP Data Object) [一]
1.简介:(PDO数据库访问抽象层,统一各种 数据库的访问接口 ) PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口.实现 PDO 接口的每个数据库驱动可以公开具体数据库 ...
- (匹配)Fire Net --hdu --1045
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1045 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- oracle中row_number() over()分析函数用法
row_number()over(partition by col1 order by col2)表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内 ...
- ggdl
\documentclass{article} \usepackage{geometry} \geometry{hmargin=1cm,vmargin=1cm} \usepackage{tikz} % ...
- Android-卖票案例static-不推荐此方式
需求描述:四个窗口一起卖票,把10张票卖完,不许多卖 先看一个错误的案例: package android.java.thread06; /** * 售票线程 */ class Booking ext ...
- 查看Linux服务器被映射的公网ip
查看Linux服务器被映射的公网ip 现在云服务器非常流行,不仅企业甚至是个人都可能拥有自己的云服务器,但是目前的云服务器厂商提供的公网IP大都是映射而来,所以在Linux服务器上执行ifconf ...
- 利用backtrace和backtrace_symbols函数打印调用栈信息
在头文件"execinfo.h"中声明了三个函数用于获取当前线程的函数调用堆栈. #include <execinfo.h> int backtrace(void * ...
- TSQL--删除登陆相关的用户
无二话,上代码 --删除登陆相关的用户 --遍历所有数据库,查找到与登录名相关联的的用户,生成删除脚本 ) SET @loginName='DBA'; DECLARE @comm NVARCHAR(M ...
- 解决oninput在输入中文时,会获取拼音的问题
(1)起因:在今天做项目测试的时候发现的问题,在用微软自带的输入法的时候,输入中文,文本框会获得拼音 如图所示: (2)解决办法:经过一段时间的百度查找,最后通过这篇文章找到了解决的方法,这里给出网址 ...
- ModelForm错误验证自定义钩子和全局钩子
当需要对model_class中字段作进一步验证,作进一步的约束时,需要使用到钩子,即claan_xxx和clean方法.其返回的errors有点不是那么好处理.看示例. 1.Model_clas ...