泛型和问号

gue*_*rda 16 java generics

我想使用通用列表,但初始化方法只返回一个List.以下代码运行良好:

List tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");
Run Code Online (Sandbox Code Playgroud)

Java指责我使用的是原始类型,我应该对列表进行参数化.所以我添加了问号参数化这个列表.

List<?> tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");
Run Code Online (Sandbox Code Playgroud)

问题是:现在该add(..)方法不再起作用了.
我无法保证列表中只包含Strings,因为我的代码中aMethodToInitializeTheColumnList()没有实现.

我的错是什么?

谢谢!

gue*_*rda 28

来自泛型教程.感谢Michael的回答!

然而,向它添加任意对象是不安全的:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Run Code Online (Sandbox Code Playgroud)

由于我们不知道c的元素类型代表什么,我们无法向其添加对象.add()方法接受类型为E的参数,即集合的元素类型.当实际类型参数为?时,它代表某种未知类型.我们传递给add的任何参数都必须是这种未知类型的子类型.因为我们不知道它是什么类型,所以我们无法传递任何内容.唯一的例外是null,它是每种类型的成员.

  • 原谅我的无知(我不是Java人).如果不起作用,有什么目的? (4认同)
  • @noloader:目的是这样的:如果你有一个类型为`Collection <?>`的方法参数,你可以传入`Collection <String>`,`Collection <Integer>`或`Collection <Whatever>` ,在方法中,您可以将这些集合的内容作为"Object"类型获取.您无法向集合中添加任何内容非常重要,因为它可确保不违反原始类型约束. (4认同)

Mic*_*rdt 18

您可能想要使用List<String>- 这就是Generics的用途,即添加有关集合中哪种对象的信息.如果您实际上要使用包含混合类型的List(通常是设计不良的标志),请使用List<Object>

有关使用通配符的更多信息,请查看泛型教程.但是在定义自己的泛型类或具有泛型参数的方法时,它们才真正相关.


Rom*_*ain 16

如果使用<?>,则表示您不会在任何地方使用参数化类型.要么转到特定类型(在您的情况下似乎List<String>)或非常通用List<Object>

  • 因为类型是*unknown*.编译不可能确定`String`是否合适,因此不允许向列表中添加`String`.(实际上,除了`null`之外,你不允许在该列表中添加任何内容.) (3认同)
  • 好吧,编译器强制实现语义一致性.你说你不会使用参数化类型,所以它不会让你.`add`方法需要一个参数,其类型是泛型参数,因此如果您没有指定,则不允许使用它. (2认同)

And*_*yle 8

在这种情况下,另一种选择是将您的列表声明为a

List<? super String>
Run Code Online (Sandbox Code Playgroud)

因为这个模型正是你所了解的.你说你不确切知道它的类型边界是什么,但从你的第二行开始,假设它必须能够包含字符串是公平的.

在我看来,这比编译更好,List<Object>因为它编码了你的不确定性,以及列表中的实际内容.基本上,你只能向它添加字符串,但是当你调用get()返回的元素时可能是任何东西(并且Java将正确地推断出这种类型Object).

在实际应用中,这之间的唯一区别List<Object>是,后者将允许tmpColumnList.add(3)或者tmpColumnList.add(new Thread())等我更喜欢它所携带的语义以及实用性.