具有列表的Java通用接口上的编译器错误<&燃气轮机;方法

具有列表的Java通用接口上的编译器错误<&燃气轮机;方法,java,generics,collections,interface,compiler-errors,Java,Generics,Collections,Interface,Compiler Errors,我不理解由以下代码导致的编译器错误。我定义了一个通用接口,请参见Task,它有两个方法:U doSomething(字符串值)和List getid()。doSomething()方法实际上使用泛型类型作为其返回值的类型,但似乎没有引起问题。getIDs()方法返回一个列表,该列表与任务类型无关,但在使用for..each语句迭代返回值时会导致问题。出现以下编译器错误 接口上的类型擦除似乎导致编译器忘记了第二个方法上声明的类型,这与泛型类型无关或者换句话说,为什么接口上的泛型类型会影响编译器如何

我不理解由以下代码导致的编译器错误。我定义了一个通用接口,请参见Task,它有两个方法:
U doSomething(字符串值)
List getid()
。doSomething()方法实际上使用泛型类型作为其返回值的类型,但似乎没有引起问题。
getIDs()
方法返回一个列表,该列表与任务类型无关,但在使用for..each语句迭代返回值时会导致问题。出现以下编译器错误

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

显然,如果我在for.之外获得对列表的引用,每个都没有问题,但不是直接的

公共类接口测试{
公共静态void main(字符串[]args){
Task Task=new MyTask();
//这里的类型没有问题
列表值=task.getIDs();
//获取此行的编译器错误
for(整数值:task.getIDs()){
}
}
}
接口任务{
U doSomething(字符串值);
列出getid();
}

接口的实现不是演示这一点的必要条件,但我不想让引用
Task=null并有答案告诉我这就是问题所在

类MyTask实现任务{
@凌驾
公共布尔doSomething(字符串值){
系统输出打印项次(值);
返回false;
}
@凌驾
公共列表getIDs(){
返回数组.asList(1,2,3,4);
}
}

错误似乎就在这里:

Task task = new MyTask();
您忘记在
任务
之后添加泛型。如果将其更改为以下选项之一,则该选项应能正常工作:

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

当使用带有泛型参数的类(或接口)时,编译器会从类中删除所有泛型类型信息,但引用不带
的类(或接口)的实例。这可能是由于与1.5版本之前的源代码兼容,您根本无法使用泛型类型信息

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

编辑:

当它提到(信用证:)时,暗示了这一点:

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

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

如果我正确解释(§4.6.类型擦除),这就是语言的“陷阱”:

类型擦除还将构造函数或方法的签名(§8.4.2)映射到没有参数化类型或类型变量的签名。构造函数或方法签名s的擦除是一个签名,由与s相同的名称和s中给出的所有形式参数类型的擦除组成

我相信这表明,如果您声明了一个类型(
Task
),该类型是使用泛型参数(
Task
)声明的,而没有所述泛型参数,则其所有函数也会丢失它们的泛型类型,无论它们是否相关。因此,编译器将
任务.getIDs()
解释为返回一个普通的
列表,而不是
列表。当然,它的迭代器会生成
对象
,而不是
整数
,从而导致您看到的编译器错误


其原因可能是与Java1.5之前产生的代码向后兼容,当时引入了泛型

它如何处理
返回新int[]{1,2,3,4}
返回数组.asList(新整数(1),新整数(2),…)?(注意,不是假设性的。尝试一下,将结果添加到问题中,以表明装箱/拆箱显然是在做一些奇怪的事情)这是一个非常好的问题;答案可能隐藏在JLS的内心深处。@arshajii:您是否将
U doSomething(字符串值)
U doSomething(U值)
更改为
U doSomething(字符串值)
?我认为发布的代码实际上并不是OP在做什么。我的猜测是,因为您声明了
Task Task
而没有泛型类型,所以它会从类定义中删除所有泛型,包括
getid
上的
。不确定这是一个bug还是一个gotcha/特性。我对所有答案都投了赞成票,因为它们都有助于我理解这个问题。来自Lone nebula的答案是,如果我用泛型定义我的任务接口,那么这可能会让编译器感到高兴。既然问题是为什么会这样,我已经接受了引用规范JLS-4.8-210的答案,但我认为引用规范的两个答案都是有价值的。问题是为什么它不能按原样工作。@arshajii他们没有资源/时间,所以他们对原始类型进行了非常粗糙的处理。类型的。。。实例方法。。。原始类型的。。。是原始类型…我相信我已经找到了适当的JLS规范,请参阅我的答案。
Task<Boolean> task = new MyTask();
Task<?> task = new MyTask();