Java 目标类型具有通配符时的泛型方法类型推断
我知道编译器使用目标类型来确定使泛型方法调用适用的类型参数。例如,在以下语句中:Java 目标类型具有通配符时的泛型方法类型推断,java,generics,type-inference,Java,Generics,Type Inference,我知道编译器使用目标类型来确定使泛型方法调用适用的类型参数。例如,在以下语句中: List<String> listOne = Collections.emptyList(); 在本例中,T的推断类型参数是String 现在考虑以下内容: List<?> listTwo = Collections.emptyList(); 这种情况下的推断类型是什么?它是物体吗?或者,由于通配符告诉编译器任何类型都是可能的,所以这并不重要?通配符的每次使用都有一个与之相关联的不同类型
List<String> listOne = Collections.emptyList();
在本例中,T的推断类型参数是String
现在考虑以下内容:
List<?> listTwo = Collections.emptyList();
这种情况下的推断类型是什么?它是物体吗?或者,由于通配符告诉编译器任何类型都是可能的,所以这并不重要?通配符的每次使用都有一个与之相关联的不同类型。通常,JLS将其称为新类型。例如,类似这样的编译器错误就是这样工作的:
List<?> list0 = ... ;
List<?> list1 = ... ;
list0.add(list1.get(0)); // error
如果您尝试以下操作,您可以开始看到这如何适合类型推断
{
List<?> list0 = ... ;
List<?> list1 = ... ;
test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}
// target type --> inferred invocation type
// v v
List<CAP#1> empty = Collections.<CAP#1>emptyList();
我用粗体强调。这些帽子。。。类型是在测试期间生成的。它向我们展示的是,当检查方法调用表达式时,list0和list1被赋予了彼此不同的类型。对于那些需要对错误进行解释的人:这是因为test声明断言两个列表必须具有相同的T
既然我们现在知道一个通配符与一个引用类型相关联,我们可以在下面的例子中看到这一点
List<?> empty = Collections.emptyList();
调用将被推断为类似于新类型的东西,其中上限是Object。或者象征性地说,编译器可能会看到
{
List<?> list0 = ... ;
List<?> list1 = ... ;
test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}
// target type --> inferred invocation type
// v v
List<CAP#1> empty = Collections.<CAP#1>emptyList();
尽管:当然,我们总是猜测一点,因为这取决于编译器如何实现这一点。从理论上讲,对于上面的emptyList的简单赋值这样的情况,它不需要做任何工作来生成正确的字节码
还有,对不起,我今天不想去。本质上,这里的类型推断是通过生成一组约束来证明方法调用应该编译还是不应该编译。中描述的算法以这种方式合并了一个通配符。通配符的每次使用都有一个与之关联的不同类型。通常,JLS将其称为新类型。例如,类似这样的编译器错误就是这样工作的:
List<?> list0 = ... ;
List<?> list1 = ... ;
list0.add(list1.get(0)); // error
如果您尝试以下操作,您可以开始看到这如何适合类型推断
{
List<?> list0 = ... ;
List<?> list1 = ... ;
test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}
// target type --> inferred invocation type
// v v
List<CAP#1> empty = Collections.<CAP#1>emptyList();
我用粗体强调。这些帽子。。。类型是在测试期间生成的。它向我们展示的是,当检查方法调用表达式时,list0和list1被赋予了彼此不同的类型。对于那些需要对错误进行解释的人:这是因为test声明断言两个列表必须具有相同的T
既然我们现在知道一个通配符与一个引用类型相关联,我们可以在下面的例子中看到这一点
List<?> empty = Collections.emptyList();
调用将被推断为类似于新类型的东西,其中上限是Object。或者象征性地说,编译器可能会看到
{
List<?> list0 = ... ;
List<?> list1 = ... ;
test(list0, list1);
}
static <T> void test(List<T> list0, List<T> list1) {}
// target type --> inferred invocation type
// v v
List<CAP#1> empty = Collections.<CAP#1>emptyList();
尽管:当然,我们总是猜测一点,因为这取决于编译器如何实现这一点。从理论上讲,对于上面的emptyList的简单赋值这样的情况,它不需要做任何工作来生成正确的字节码
还有,对不起,我今天不想去。本质上,这里的类型推断是通过生成一组约束来证明方法调用应该编译还是不应该编译。中描述的算法以这种方式合并了一个通配符
这种情况下的推断类型是什么?它是物体吗?或者不是
由于通配符告诉编译器任何类型都是
可能吗
在某种程度上,这是一个哲学问题,因为类型参数对编译的字节码没有任何影响,所以具体是什么并不重要。唯一重要的是是否不可能满足边界和上下文。只要编译器能够证明存在某种可以工作的类型,那么在我看来,它应该能够继续编译,而不需要拿出实际的类型
这种情况下的推断类型是什么?它是物体吗?或者不是
由于通配符告诉编译器任何类型都是
可能吗
在某种程度上,这是一个哲学问题,因为类型参数对编译的字节码没有任何影响,所以具体是什么并不重要。唯一重要的是是否不可能满足边界和上下文。只要编译器能够证明存在某种可以工作的类型,那么在我看来,它应该能够继续编译,而不需要拿出实际的类型。?不是任何类型,它是未知类型。除此之外,奥利弗说了些什么。作为一个切线,不清楚你会对一个列表做什么,因为你不能把任何东西放进去。?这意味着您不打算在列表中使用任何需要参数或返回类型t的方法。如果这样做,您将得到一个编译错误。@OliverCharlesworth确实是,我不使用这个
在实际代码中,但只是想知道这种情况下的推断类型。@DannyDaglas该值为null时没有编译错误。?不是任何类型,它是未知类型。除此之外,奥利弗说了些什么。作为一个切线,不清楚你会对一个列表做什么,因为你不能把任何东西放进去。?这意味着您不打算在列表中使用任何需要参数或返回类型t的方法。如果这样做,您将得到一个编译错误。@OliverCharlesworth确实是,我没有在实际代码中使用它,只是想知道这种情况下的推断类型。@DannyDaglas该值为null时没有编译错误。