2011-03-25 52 views
7

在Java中的for-each循环中使用泛型时出现奇怪的编译器错误。这是一个Java编译器错误,还是我真的在这里错过了一些东西?为什么Java编译器抱怨使用foreach与原始类型?

这里是我的全班同学:

public class Generics<T extends Object> { 
    public Generics(T myObject){ 
    // I didn't really need myObject 
    } 

    public List<String> getList(){ 
    List<String> list = new ArrayList<String>(); 
    list.add("w00t StackOverflow"); 
    return list; 
    } 

    public static void main(String...a){ 
    Generics generics = new Generics(new Object()); 
    for(String s : generics.getList()){ 
     System.out.println(s); 
    } 
    } 
} 

编译器抱怨与换将线路:“类型不匹配无法从元素类型的对象转换为字符串”
如果我让这个微妙的变化,它编译:

public static void main(String...a){ 
    Generics<?> generics = new Generics(new Object()); 
    for(String s : generics.getList()){ 
    System.out.println(s); 
    } 
} 

我知道getList()不使用泛型,但它使用它们在我认为是一个完全无关的方式。我可以理解这一点,如果我试图迭代T类型的东西,并且getList()返回了List<T>什么的,但这不是这种情况。 getList()的返回类型应该与T完全无关,不应该在乎我是否使用原始类型作为我的泛型对象或不是......对吗?这些不应该完全无关,还是我真的在这里错过了一些东西?

注意,代码也编译如果我这样做,我认为应该是等同于第一以及:

public static void main(String...a){ 
    Generics generics = new Generics(new Object()); 
    List<String> list = generics.getList(); 
    for(String s : list){ 
    System.out.println(s); 
    } 
} 
+1

''没有比'不同'。你不是在制作你的类的通用版本,而是在制作原始类型。这给我们带来了一个问题,为什么你的类是通用的?你使用T的唯一地方是在构造函数中,你不使用该引用。 – unholysampler 2011-03-25 18:45:20

+0

我用'',因为我只是需要一些例子。真正的代码显然是别的东西,它确实使用T ...它只是以与getList()完全无关的方式使用T。 – 2011-03-25 18:49:34

+0

与你的问题无关,但我会让构造函数为泛型cls),所以你不必实例化一个类型为T的对象来构造这个Generics类。 – MeBigFatGuy 2011-03-25 19:55:26

回答

11

不同之处在于,当您使用原始类型时,全部成员签名中的通用引用也会转换为其原始表单。因此,有效地你打电话现在有这样一个签名的方法:

List getList() 

现在,至于为什么你的最终版本编译 - 虽然它,有一个警告,如果您使用-Xlint

Generics.java:16: warning: [unchecked] unchecked conversion 
    List<String> list = generics.getList(); 
             ^

这类似于:

List list = new ArrayList(); 
List<String> strings = list; 

...这也编译,但-Xlint下一个警告。

故事的寓意:不要使用原始类型!

+0

我很惊讶*成员签名中的所有通用引用被转换为其原始表单。这样做的理由是什么(除了Sun感觉就像这样)? – 2011-03-25 19:49:19

+4

@Michael:JLS在第4.8节(原始类型)中包含了这个讨论:“原始类型与通配符密切相关,两者都基于存在类型。原始类型可以被认为是通配符,其类型规则故意不适合,以适应与遗留代码的交互。“换句话说,原始类型通常不应该出现在新代码中,但他们试图避免让旧代码无法编译,即使它至少是可疑的。 – 2011-03-25 19:51:40

+0

非常有趣。我已经知道要避免使用原始类型(一个同事写代码来声明变量),但是这突出表明它确实很重要。 – 2011-03-25 20:04:58

3

更改线路

Generics generics = new Generics(new Object()); 

Generics<?> generics = new Generics<Object>(new Object()); 

问题的根源在于您使用的是raw type,所以的类型方法是List,而不是List<String>

+0

泛型不会是字符串类型的泛型......这是整个问题。字符串与泛型类型无关。不管T是什么,'getList()'应该返回'List '。 – 2011-03-25 18:50:44

+0

@Michael McGowan,好点。但是在声明处必须有一些与type参数关联的类型。 '泛型泛型= new泛型(...);'会很好,以不安全的转换警告为模。 – 2011-03-25 19:01:56

+0

@Michael McGowan,请注意,如果你所做的只是从类声明中删除类型参数'',那么它就可以工作。 – 2011-03-25 19:03:56

-1

我对你的代码做了一些调整。 您在您的评论中看到您的构造函数中不需要Object,因此请将其删除以避免混淆。其次,如果仿制药将是通用的,正确初始化它

这里是新的主力将是什么样子

public static void main(String...a){ 
    Generics<String> generics = new Generics<String>(); 
    for(String s : generics.getList()){ 
     System.out.println(s); 
    } 
    } 
+0

泛型不会是字符串类型的泛型......这是重点。字符串与泛型类型无关。 – 2011-03-25 18:48:18

+0

我想你误解了我的观点。如果你看代码,你有getList()方法返回一个列表。如果我们想让代码非常干净,我们可以从getList()方法中的代码中除去泛型部分。你需要帮助才能编译,而不是他的方法是对/错。 – Sean 2011-03-25 19:22:52

+0

如果您在类级别上保留通用减速度,则会打开getList()方法以删除现在存在的硬编码。 – Sean 2011-03-25 19:29:34

相关问题