2015-10-23 72 views
-1

假设你有一些类T类型:Java泛型 - 何时?通配符需要

class MyClass<T extends SomeOtherClass> { 
    .... 
} 

现在,你想这个类的实例存储到一个集合,但你并不真正关心的类型。我会表达如下:

private final List<MyClass> entries = new ArrayList<>(); 

是否有任何好的理由/优势写下列代替?

private final List<MyClass<?>> entries = new ArrayList<>(); 

甚至:

private final List<MyClass<? extends SomeOtherClass> entries = new ArrayList<>(); 

我自己只能找到一个不好的理由这样做:每当MyClass变化(例如添加另一种类型)类型定义,你必须改变全局代码中的List<MyClass<?>>List<MyClass<? extends SomeOtherClass>>定义也是如此。

更新

要更新我的问题:

为什么不是编译器能够跟踪的MyClass的类型,当你写List<MyClass>(甚至List<MyClass<? extends SomeOtherClass>>)?他知道MyClass被定义为MyClass<T extends SomeOtherClass>,那么当你写List<MyClass>时,他为什么不能这样做呢?

换句话说,为什么List<MyClass>不等于List<MyClass<?>>(或甚至List<MyClass<? extends SomeOtherClass>>)?编译器拥有所有的信息来自己做出这个结论,afaik。

+1

看看这个伟大的答案:http://stackoverflow.com/a/3009779/2215166 – christophetd

+2

http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why -shouldnt-we-use-it潜在相关。还有'?扩展SomeOtherClass'当然是有用的,因为它提供了有关类不兼容的编译时错误,如果你真的只想要实现特定接口的泛型,就可以节省许多麻烦。 – CollinD

+3

[Java泛型中的问号的类型参数是什么意思?]的可能重复(http://stackoverflow.com/questions/3009745/what-does-the-question-mark-in-java-generics-type-参数平均) – Joe

回答

1

?通配符在您不需要再次引用类型时非常有用,因此您不需要生成特定的标识符。

您的第一小段以class MyClass<T extends SomeOtherClass>开头。这是必要的时候,T很重要,也许要声明一个字段参数或返回类型。例如:

class MyClass<T extends SomeOtherClass> { 
    private final List<T> aListOfT; 
    public T getSomething() { 
     return this.aListOfT.get(0); 
    } 

由于MyClass是一个通用型,它的所有引用应限定,以避免避免运行时错误。因此,当你声明List<MyClass>时,你会得到一个编译器警告,你使用原始类型MyClass。如果您不在代码中的位置,那么MyClass合格的是哪种类型,然后您使用?来告诉编译器,您不在意并让它跟踪该类型并检查所有操作的有效性。

+0

为什么当编写'List '时编译器不能跟踪类型?他知道'MyClass'被定义为'MyClass ',所以当你编写'List ''时,他为什么不能这样做呢? –

+1

'MyClass'不完整。当你忽略它时,编译器不知道'T'是什么。很像“List”是一种原始类型。如果你不在意列表中包含的是什么,那么你就写下'List '。编译器会在需要将其显示为错误时将其显示为“capture-1-of-?”(或类似的东西)。每个'?'都是自己的类型,与其他类型不兼容。 – dsh

0

您的第一个声明意味着,您未提供任何有关未来反射系统的通用数据的信息,可以使用插件编写,这些插件是为您的主程序编写的。

第二个声明告诉他们该字段包含一个Object泛型。

第三个是更具体的,它意味着,反射系统知道,这个领域是什么细节。

0

使用第一种类型,java将假定泛型类型为Object。原因是,泛型在1.5版本中引入。在此之前,集合类将所有对象存储为对象。出于兼容性原因,不提供通用参数意味着您正在使用对象。

第二种类型只是说你不知道或不关心它是什么类型。当代码被编译时,这些信息被保存。所以其他可能使用你的代码的程序员会知道你并不在乎。

由于java的类型擦除,这两者在运行时没有区别。

有了上次的形式你说: 我不在乎它是什么,但它必须是SomeOtherClass或推导类型。这是一样的:

List<MyClass<SomeOtherClass>> 

你也可以做它周围的其他方法:

List<MyClass<? super SomeOtherClass>> 

说,你不在乎它是什么类型,除非它是SomeOtherClass的超类型。