使用 List<> 方法的 Java 泛型接口上的编译器错误

我不明白以下代码导致的编译器错误。我定义了一个通用接口,请参阅任务,使用两种方法:和。doSomething() 方法实际上使用泛型类型作为其返回值的类型,但似乎不会引起问题。该方法返回一个 List,该列表与 Task 的类型无关,但在使用 for.. 时会导致问题。每个语句以循环访问返回值。发生以下编译器错误。U doSomething(String value)List<Integer> getIDs()getIDs()

error: incompatible types
    for (Integer value : task.getIDs()){
required: Integer
found:    Object

接口上的类型擦除似乎导致编译器忘记了第二个方法上的声明类型,这与泛型类型无关。或者换句话说,为什么接口上的泛型类型会影响编译器如何理解getIDs()方法上的返回值,特别是在for.的上下文中。每个语句?

显然,如果我得到参考列表之外的for..每个都没有问题,但不是直接的。

public class InterfaceTest {
   public static void main(String[] args) {
      Task task = new MyTask();
      // no complaints about the type here     
      List<Integer> values = task.getIDs();

      // getting a compiler error for this line
      for (Integer value : task.getIDs()){

      }
   }
}


interface Task<U>{
   U doSomething(String value);
   List<Integer> getIDs();
}

接口的实现不是证明这一点所必需的,但我不想离开参考并让答案告诉我这就是问题所在。Task task = null;

class MyTask implements Task<Boolean>{

   @Override
   public Boolean doSomething(String value) {
      System.out.println(value);
      return false;
   }

   @Override
   public List<Integer> getIDs() {
      return Arrays.asList( 1, 2, 3, 4 );
   }
}

答案 1

正在发生的事情是,当使用带有泛型参数的类(或接口)但引用和不包含(即该类型)的实例时,编译器会从类中删除所有泛型类型信息。这可能是由于与 1.5 之前的源代码兼容,您根本无法使用泛型类型信息。<T><T>raw

考虑一下在 Java 1.4 编译器上编写代码和编译的情况。您希望使用使用泛型的库。当您从该库中引用具有泛型参数作为原始类型的类型时,编译器将强制使用不带泛型参数。

编辑:

Image caption JLS-4.8-210在提到这一点时提到了这一点(图片来源:zhong-j-yu):

未从其超类或超接口继承的原始类型 C 的构造函数 (§8.8)、实例方法 (§8.4、 §9.4) 或非静态字段 (§8.3) M 是原始类型,该类型对应于在对应于 C 的泛型声明中擦除其类型。

这仍然感觉像是一个陷阱,但可能是出于某种原因。


答案 2

错误似乎在这里:

Task task = new MyTask();

您忘记在 之后添加泛型。如果您将其更改为以下之一,它应该可以工作:Task

Task<Boolean> task = new MyTask();
Task<?> task = new MyTask();