编译错误与generics

test1和test2之间的区别在哪里? 为什么test1中的编译错误?

import java.util.ArrayList; import java.util.Collection; class MyType { } class MyClass { private Collection myTypes = new ArrayList(); private Collection myTs = new ArrayList(); public Collection getMyTypes() { return myTypes; } public Collection getMyTs() { return myTs; } } public class TestSimple { public void test1() { MyClass myClass = new MyClass(); for (MyType myType : myClass.getMyTypes()) { } } public void test2() { MyClass myClass = new MyClass(); Collection myTypes = myClass.getMyTypes(); for (MyType myType : myTypes) { } } public void test3() { MyClass myClass = new MyClass(); for (Long myType : myClass.getMyTs()) { } } } 

如果你在一个类上定义一个generics约束,然后在没有提供任何generics约束的情况下实例化该类(也就是说,你完全不使用<> ),那么你刚刚进入了原始类型的领域,其中没有什么是再也一样了。

根据Java语言规范 :

原始类型的使用仅允许作为遗留代码兼容性的让步。 强烈建议不要在将通用性引入Java编程语言之后编写的代码中使用原始类型。 未来版本的Java编程语言可能会禁止使用原始类型。

根据Angelika Langer出色的Java Generics FAQ ,

原始类型的方法或构造函数具有在类型擦除之后将具有的签名。 如果擦除更改了参数类型,则对原始类型的方法或构造函数调用会生成未经检查的警告。

因此,通过将MyClass构造为原始类型(即,作为MyClass而不是MyClass ), 您完全选择了generics ,并且getMyTypes()的返回类型现在是原始类型Collection ,而不是Collection 。 因此,您不能使用类型为MyType的增强型语法,而是必须使用Object

当然,更好的解决方案就是使用MyClass (而不仅仅是MyClass ),当您指的是未知参数化类型的MyClass时。

我已将您的问题分离到一个较小的示例,我将在下面显示

 import java.util.*; public class TestSimple { static class MyClass { private Collection myTypes = new ArrayList(); public Collection getMyTypes() { return myTypes; } } public void test1() { MyClass myClass = new MyClass(); for (String myType : myClass.getMyTypes()) { } } } 

我怀疑所有类型的信息都被剥夺了,除非你特别说明。 所以我的建议是改变你的声明:

 before: MyClass myClass = new MyClass(); after: MyClass myClass = new MyClass(); 

Java对原始类型过于苛刻。 如果使用原始类型的generics类,则忽略类中的所有generics信息,即使是与类的类型参数无关的无效信息也是如此。

 class A implements List Set var; 

如果你使用原始A ,那么它被视为

 class A implements List Set var; 

这种严厉的处理是没有必要的; 他们可能不认为原始类型需要太多资源,因此他们采取了简单的方法,从原始类型中不加选择地删除每个通用信息。

test2由于您尚未参数化MyClass ,因此getMyTypes()将有效地返回Collection ,而Collection不能分配给Collection