Java泛型 - 什么时候?需要通配符

时间:2015-10-23 16:09:12

标签: java generics wildcard

假设您有一些类型为T的课程:

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<?>>或{{1}你的代码中也有定义。

更新

更新我的问题:

为什么编译器在写List<MyClass<? extends SomeOtherClass>>(甚至MyClass)时无法跟踪List<MyClass>的类型?他知道List<MyClass<? extends SomeOtherClass>>被定义为MyClass,所以当你写MyClass<T extends SomeOtherClass>时,他为什么不能/允许这样做?

换句话说,为什么List<MyClass>不等于List<MyClass>(甚至List<MyClass<?>>)?编译器有自己的所有信息,afaik。

3 个答案:

答案 0 :(得分: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。如果您不关心代码中的那个位置?符合哪种类型,那么您使用val1 = df1['val1'] val2 = df1['val2'] val11 = df2['val11'] val22 = df2['val22'] SameOrNot = None if val1 == val11 and val2 == val22: SameOrNot = True else: SameOrNot = False pd.to_csv('output.csv', header = [val1, val2, val11, val22, SameOrNot]) 告诉编译器您不关心并让它跟踪类型并检查所有操作的有效性。

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

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

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

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

用最后一个表格你说: 我不在乎它是什么,但它必须是SomeOtherClass或派生类型。这与:

相同
List<MyClass<SomeOtherClass>>

您也可以反过来这样做:

List<MyClass<? super SomeOtherClass>>

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

相关问题