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 be Object, 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<? extendsV>, 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的更多相关文章

  1. [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 ...

  2. ERROR: HHH000091: Expected type: java.sql.Timestamp, actual value: java.lang.Integer

    在将MySql的数据对应到Java的实体类的时候, 遇到了错误 关键点: Hibernate从mysql数据库查出来的Timestamp类型的数据, 会被Hibernate(或者是数据库连接池Drui ...

  3. Run Configurations(Debug Configurations)->Arguments里填写program arguments和VM arguments

    如图: 1.program arguments存储在String[] args里 2.VM arguments设置的是虚拟机的属性,是传给java虚拟机的.KV形式存储的,是可以通过System.ge ...

  4. Javac之关于方法的调用1

    方法的调用从Attr类的visitApply()方法进入,如下: /** Visitor method for method invocations. * NOTE: The method part ...

  5. Javac之关于方法的选择

    15.12. Method Invocation Expressions 15.12.1. Compile-Time Step 1: Determine Class or Interface to S ...

  6. 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 ...

  7. 阅读The Java® Language Specification需要知道的术语

    Null Pointer Exception,简称NPE 在java中,static final修饰的是常量.根据编译器的不同行为,常量又可分为编译时常量和运行时常量. 举例说明吧 public st ...

  8. parameters arguments 形式参数 实际参数

    parameter和argument的区别 – 笑遍世界 http://smilejay.com/2011/11/parameter_argument/ https://en.wikipedia.or ...

  9. Spock - Document -04- Interaction Based Testing

    Interaction Based Testing Peter Niederwieser, The Spock Framework TeamVersion 1.1 Interaction-based ...

随机推荐

  1. 在 JNI 编程中避免内存泄漏与崩溃

    JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互——在 Java 程序中 ...

  2. js 面向对象 定义对象

    js面向对象看了很多,却没有完全真正的理解,总是停留在一定的阶段,这次再认真看一下. 面向对象包含两种:定义类或对象:继承机制:都是通过工厂模式,构造函数,原型链,混合方法这四个阶段,原理也一样,只是 ...

  3. Hibernate的查询方式汇总

    分别是HQL查询,对象化查询Criteria方法,动态查询DetachedCriteria,例子查询,sql查询,命名查询. 如果单纯的使用hibernate查询数据库只需要懂其中的一项就可以完成想要 ...

  4. [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 ...

  5. Linq to Object 的简单使用示例

    语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,可为 C# 和 Visual Basic 语言语法提供强大的查询功能. LINQ 引入了标准易学的数据查询和更新 ...

  6. JS代码指导原则

    一.什么是平稳退化? 如果含有JS代码的网页在用户浏览器不支持JS(或者禁用JS)时,用户仍然能够顺利浏览(网站功能正常,只是视觉效果可能差一些),那么这个网页就能够平稳退化 网页能够平稳退化是很必要 ...

  7. ABP框架中微服务跨域调用其它服务接口

    AjaxResponse为ABP自动包装的JSON格式 /// <summary> /// 通过地址和参数取得返回OutPut数据 /// </summary> /// < ...

  8. C#存储过程调用的三个方法

    //带参数的SQL语句 private void sql_param() { SqlConnection conn = new SqlConnection("server=WIN-OUD59 ...

  9. .Net core,EFCore 入门

    我在百度上搜了一下.net  core和efcore 入门案例.好多博客都是大概说了一下做法,对于小白而言还是一头雾水,我今天就抽出一点时间,写一个详细的入门小案例,就一张表没有什么业务可言.主要是操 ...

  10. .net core AOP之Filter

    当我们进行项目开发时,往往在开发过程中需要临时加入一些常用功能性代码,如身份验证.日志记录.异常获取等功能.如果每个方法中都加入这些功能性代码的话,无疑使项目显得过于臃肿,代码繁杂.这时候就要加入过滤 ...