Java Generics:关于使用泛型方法进行类型捕获和生成推断的问题

yap*_*m01 7 java generics

这是我之前的问题的后续,但由于前一个线程很长,我决定启动另一个与几乎相同主题相关的线程.

public class GenericMethodInference {

static <T> void test1(T t1, T t2) {}
static <T> void test3(T t1, List <T> t2) {}  
static <T> void test4(List <T> t1, List <T> t2) {}

public static void main(String [] args) {

    List <Object> c = new LinkedList<Object>();
    List <? extends Object> d = new ArrayList<Integer>();
    List e = new ArrayList<Integer>();

    test1("Hello", new Integer(1)); // ok clause (1)
    GenericMethodInference.<Object>test1("Hello", new Integer(1)); // ok clause (2)
    test3("Hello", c); // ok clause (3)
    test4(d,d) // clause (4) Error due to different type capture generated

}
Run Code Online (Sandbox Code Playgroud)

注意:如果将光标移到每个子句上,您将看到在Eclipse上生成和显示的推理:

一个.条款(1)将产生<?extends Object> test1 <?extends Object,?extends Object>
b.第(2)款将完全产生实际类型参数
c中定义的内容.第(3)条将产生<Object> test3 <Object,List <Object >>

问题:

  1. 为什么第(1)条没有产生<Object>?由于<Object>的工作方式如第(2)项所示,为什么<?扩展Object>生成而不是?
  2. 为什么第(3)条产生<Object>而不是<?extends Object>?
  3. 由于第(4)条使用相同的变量,为什么2个不同的类型捕获产生的事件尽管使用的参数是相同的变量d?

Pau*_*ora 3

为什么子句(1)没有产生<Object>?既然<Object>的工作原理如第(2)条所示,为什么<? 扩展对象>被生产代替?

这是三个问题中最好的一个。我的想法是,编译器/Eclipse 不想假设必然是和之间推断的Object类型,因此它会谨慎行事。正如@bringer128指出的,并且都实现了- 所以这些类型也是方法的推断类型的候选类型。TStringIntegerStringIntegerSerializableComparable

值得注意的是,以下代码给出了编译器错误“非法类型开始”:

GenericMethodInference.<? extends Object>test1("Hello", new Integer(1));
Run Code Online (Sandbox Code Playgroud)

这是因为将通配符指定为方法的类型参数是无效的。因此,您在工具提示中看到的事实与编译器/Eclipse 报告此信息的功能的微妙有关 - 它仅确定了在T其范围内的信息,而不是确定了它是什么。

请记住,Java 的泛型实现只是为了程序员的方便/理智。一旦编译成字节码,类型擦除将消除任何T. 因此,在检查时,编译器只需要确保可以推断出有效的值,但不一定可以推断出它是什么。T


为什么子句 (3) 产生 <Object> 而不是 <?扩展对象>?

List<Object>因为在这种情况下,将 a传入预期 a 的位置这一事实List<T>告诉编译器这T正是Object


既然第(4)条使用了相同的变量,为什么即使使用的参数是相同的变量d,也会生成2个不同类型的捕获?

编译器假设d实际上引用同一个对象是不安全的,即使在评估参数之间也是如此。例如:

test4(d,(d = new ArrayList<String>()));
Run Code Online (Sandbox Code Playgroud)

在这种情况下,aList<Integer>将被传递到第一个参数,an 将List<String>被传递到第二个参数 - 两者都来自d. 由于这种情况是可能的,因此编译器更容易安全行事。