2011-12-20 144 views
9

我刚碰到一些我不明白的东西。为什么不是每个循环低于合法时,当第二个相同的是?Java泛型和返回类型

public interface SomeInterface<T> { 
    List<SomeNamedObject> getObjects(); 
    void doSomething(P1 p1, T p2); 
} 

public class SomeNamedObject { 
    private String text; 
} 

public class Clazz { 

    private SomeInterface someInterface; 

    ... 

    public void someMethod() { 
     // Error Type mismatch: cannot convert from element type Object to TestClass.SomeNamedObject 
     for (SomeNamedObject someNamedObject : someInterface.getObjects()) { 
      // This loop won't compile as the someInterface.getObjects returns just a List and not a List<SomeNamedObject> 
     } 

     // Warning Type safety: The expression of type List needs unchecked 
     // conversion to conform to List<TestClass.SomeNamedObject> 
     List<SomeNamedObject> objects = someInterface.getObjects(); 
     for (SomeNamedObject someNamedObject : objects) { 
      // This loop compiles 
     } 
    } 
} 
+0

不是一个错误,它是一个擦除和原始类型的问题。 – Stefan 2011-12-20 18:26:25

+0

我没有看到问题可能是什么。你可以发布实际的堆栈跟踪(只是前几行)。我猜你的全班学生需要“SomeInterface ”,但这个例子并不需要“”也许里面有东西吗? – Jay 2011-12-20 18:27:07

+1

@Jay他的someInterface的声明没有指定泛型类型,然后Java退回到原始类型,并且方法签名更改为返回原始列表(请参阅答案)。他应该提到关于对象分配的警告。 – Stefan 2011-12-20 18:34:47

回答

18

因为你的实例变量private SomeInterface someInterface没有指定其泛型类型参数,那么所有使用泛型是someInterface禁用。这意味着someInterface.getObjects()具有原始返回类型List而不是List<SomeNamedObject>。这是第一个例子不能编译的原因。

在第二个示例中List<SomeNamedObject> objects = someInterface.getObjects()正在为列表显示一个明确的类型。当你这样做时,你会看到一个警告,但因为不能保证类型安全。如果getObjects()被定义为只有List getObjects()而没有类型参数,这与您会看到相同的行为。

+0

它可能是原文中的一个错字,但'SomeInterface '不使用'T'来指定被返回的'List'的通用类型,它被硬编码为'SomeNamedObject'。所以,即使实例变量没有输入,它也不应该影响返回的List。 – 2011-12-20 18:29:20

+5

如果通用参数未在'someInterface'声明中指定,那么即使'SomeInterface'中的* all *泛型类型不依赖于'T',也会被忽略/禁用。 – mikej 2011-12-20 18:32:13

+0

非常有趣,虽然奇特。 – 2011-12-20 18:34:04

3

您应该注意,当您在第二个循环之前对对象赋值时会得到编译器警告。

Type safety: The expression of type List needs unchecked conversion to conform to 
List<TestClass.SomeNamedObject> 

这会告诉你,由于某种原因,你的getObjects()方法返回一个非泛化的List。这解释了为什么第一个循环不能编译。

因为你忘了泛型化您参考:如果你不泛型化这一切都将使用原始类型,包括申报方法的签名

private SomeInterface someInterface; 

。意味着它返回一个列表生对象,而不是一个列表<SomeNamedObject> 的像做

private SomeInterface<Object> someInterface; 

,它应该工作。