简体   繁体   English

目标类型具有通配符时的泛型方法类型推断

[英]Generic method type inference when the target type has a wildcard

I understand that the compiler uses the target type to determine the type argument that makes the generic method invocation applicable. 我知道编译器使用目标类型来确定使通用方法调用适用的类型参数。 For instance, in the following statement: 例如,在以下语句中:

List<String> listOne = Collections.emptyList();

where the Collections.emptyList has a type parameter T in its signature 其中Collections.emptyList在其签名中具有类型参数T

public static final <T> List<T> emptyList() {

In this case, the inferred type argument for T is String . 在这种情况下, T的推断类型参数为String

Now consider the following: 现在考虑以下几点:

List<?> listTwo = Collections.emptyList();

What is the inferred type in this case? 在这种情况下,推断的类型是什么? Is it Object ? Object吗? Or it doesn't really matter due to the wildcard telling the compiler any type is possible? 还是因为通配符告诉编译器任何类型都是可能的?

Each usage of a wildcard has a distinct type associated with it. 通配符的每种用法都有与之关联的不同类型。 (Usually the JLS refers to this as being a "fresh type".) This is how for example a compiler error like this works: (通常,JLS将此称为“新鲜类型”。)例如,这就是这样的编译器错误的工作方式:

List<?> list0 = ... ;
List<?> list1 = ... ;
list0.add(list1.get(0)); // error

Because it's the case that list0 and list1 are given separate types by the compiler such that for the most part 因为在这种情况下,编译器会为list0list1分别指定不同的类型,因此大多数情况下

reference_type_of(List<?>) != reference_type_of(List<?>)

You can begin to see how this fits in to type inference if you try something like 如果您尝试类似的操作,则可以开始了解它如何适合于推论

{
    List<?> list0 = ... ;
    List<?> list1 = ... ;
    test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}

Where the compiler emits an error that actually tells us a little bit about the types that it has generated for list0 and list1 . 编译器发出错误的地方实际上告诉我们一些有关list0list1生成的类型的信息。

error: method test in class Ideone cannot be applied to given types;
    test(list0, list1);
    ^
  required: List<T>,List<T>
  found: List<CAP#1>,List<CAP#2>
  reason: no instance(s) of type variable(s) T exist so that
          argument type List<CAP#2> conforms to formal parameter type List<T>
  where T is a type-variable:
    T extends Object declared in method <T>test(List<T>,List<T>)
  where CAP#1,CAP#2 are fresh type-variables:
    CAP#1 extends Object from capture of ?
    CAP#2 extends Object from capture of ?

(My emphasis in bold.) These CAP#... types were generated during capture conversion . (我的粗体为粗体。)这些CAP#...类型是在捕获转换期间生成的。 What it's showing us is that when the method invocation expression was examined, list0 and list1 were given distinct types from each other. 它向我们显示的是,当检查方法调用表达式时, list0list1彼此具有不同的类型。 (And for those that need an explanation for the error: it's because the declaration of test asserts that both Lists must have the same T .) (对于那些需要解释错误的人:这是因为test声明断言两个List必须具有相同的T

So since we now know that a wildcard gets associated a reference type, we can see that in a case like 因此,由于我们现在知道通配符与引用类型相关联,因此可以看到

List<?> empty = Collections.emptyList();

The invocation will be inferred as something like "a fresh type where the upper bound is Object". 调用将被推断为“上限为对象的新鲜类型”。 Or symbolically we could say the compiler might see something like 或象征性地,我们可以说编译器可能会看到类似

// target type       -->       inferred invocation type
//     v                           v
List<CAP#1> empty = Collections.<CAP#1>emptyList();

Although: of course we are always guessing a little bit because it's up to the compiler how it implements this. 尽管:当然,我们总是会猜测一点,因为这取决于编译器如何实现。 In theory, for a case like the above trivial assignment of emptyList() , it would not have to do work to generate the correct bytecode. 从理论上讲,对于上述琐碎的emptyList()赋值情况,它不必做任何工作来生成正确的字节码。

Also, I am sorry, I don't feel like spec scouring today. 另外,很抱歉,我今天不喜欢规格检查。 Essentially the type inference here works by generating a set of constraints to demonstrate that the method invocation should or should not compile. 本质上,这里的类型推断通过生成一组约束来证明方法调用应该或不应该编译而起作用。 The algorithm described in 18.5.2 incorporates a wildcard in this way. 18.5.2中描述的算法以这种方式合并了通配符。

What is the inferred type in this case? 在这种情况下,推断的类型是什么? Is it Object? 是对象吗? Or it doesn't really matter due to the wildcard telling the compiler any type is possible? 还是因为通配符告诉编译器任何类型都是可能的?

On one level, it's kind of a philosophical question, because the type argument does not have any effect on the compiled bytecode, so it doesn't really matter what it is specifically. 在一个层面上,这是一个哲学问题,因为类型实参对编译后的字节码没有任何影响,因此它的具体含义并不重要。 The only thing that matters is whether or not it's impossible to satisfy the bounds and context. 唯一重要的是是否无法满足界限和上下文。 As long as the compiler can prove that there exists some type that could work, then in my opinion, it should be able to go ahead and compile it without needing to come up with an actual type. 只要编译器可以证明存在某种可以使用的类型,那么我认为,它应该能够继续进行编译,而无需提出实际的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM