目标类型具有通配符时的通用方法类型推断 [英] Generic method type inference when the target type has a wildcard
问题描述
我知道编译器使用目标类型来确定使泛型方法调用适用的类型参数。例如,在以下语句中:
List< String> listOne = Collections.emptyList();
其中 Collections.emptyList
有一个类型参数 T
在其签名中
public static final< T>列表与LT; T> emptyList(){
在这种情况下, T
是字符串
。
现在考虑以下几点:
列表<?> listTwo = Collections.emptyList();
这种情况下的推断类型是什么?它是 Object
?或者它并不重要,因为通配符告诉编译器任何类型都是可能的?
通配符的每个用法都有与之相关的独特类型。 (通常JLS将这称为新鲜类型)。这就是例如这样的编译器错误的作用:
列表与LT;?> list0 = ...;
列表<?> list1 = ...;
list0.add(list1.get(0)); //错误
因为 list1
被编译器赋予不同的类型,这样大多数情况下
reference_type_of(List<>)!= reference_type_of(List>)
如果您尝试类似于
{
列表<?> ; list0 = ...;
列表<?> list1 = ...;
test(list0,list1);
}
static< T> void test(List list0,List< T> list1){}
一个错误实际上告诉了我们一些关于为 list0
和 list1
产生的类型。
错误:类Ideone中的方法测试不能应用于给定的类型;
test(list0,list1);
^
required:List< T>,List< T>
found:List< CAP#1>,List< CAP#2>
原因:没有类型变量T的实例存在,所以
参数类型列表< CAP#2>符合形式参数类型List< T>
其中T是一个类型变量:
T extends在方法< T> test(List< T>,List< T>)中声明的Object
< CAP#2是新鲜的类型变量:
CAP#1扩展了Object从捕获的?
CAP#2扩展了对象来捕获?
(我强调以粗体显示。) 因为我们现在知道一个通配符与一个引用类型相关联,所以我们可以看到,在像 调用将被推断为类似上限为Object的新鲜类型。或者象征性地我们可以说编译器可能会看到类似于 虽然:当然我们总是猜测一下,因为它取决于编译器如何实现这个。理论上,对于像 另外,我很抱歉,我今天不喜欢spec spec淘宝。基本上,这里的类型推断通过生成一组约束来演示方法调用应该或不应该编译。在 18.5.2中描述的算法以这种方式合并通配符。 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: where the In this case, the inferred type argument for Now consider the following: What is the inferred type in this case? Is it 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: Because it's the case that You can begin to see how this fits in to type inference if you try something like Where the compiler emits an error that actually tells us a little bit about the types that it has generated for (My emphasis in bold.) These So since we now know that a wildcard gets associated a reference type, we can see that in a case like 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 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 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. 这篇关于目标类型具有通配符时的通用方法类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! CAP#...
类型是在捕获转换。它向我们展示的是,当检查方法调用表达式时, list1
被赋予了彼此不同的类型。 (对于那些需要对错误进行解释的人:这是因为 test
声明声明两个列表必须具有相同的 T $ c
列表<?> empty = Collections.emptyList();
// target type - >推断的调用类型
// v v
List< CAP#1> empty = Collections。< CAP#1> emptyList();
emptyList()
这样简单的赋值的情况,它不需要工作来产生正确的字节码。
List<String> listOne = Collections.emptyList();
Collections.emptyList
has a type parameter T
in its signaturepublic static final <T> List<T> emptyList() {
T
is String
.List<?> listTwo = Collections.emptyList();
Object
? Or it doesn't really matter due to the wildcard telling the compiler any type is possible?List<?> list0 = ... ;
List<?> list1 = ... ;
list0.add(list1.get(0)); // error
list0
and list1
are given separate types by the compiler such that for the most partreference_type_of(List<?>) != reference_type_of(List<?>)
{
List<?> list0 = ... ;
List<?> list1 = ... ;
test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}
list0
and list1
.
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 ?
CAP#...
types were generated during capture conversion. What it's showing us is that when the method invocation expression was examined, list0
and list1
were given distinct types from each other. (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
.)List<?> empty = Collections.emptyList();
// target type --> inferred invocation type
// v v
List<CAP#1> empty = Collections.<CAP#1>emptyList();
emptyList()
, it would not have to do work to generate the correct bytecode.