【问题标题】:Generics and the question mark泛型和问号
【发布时间】:2009-12-03 13:50:49
【问题描述】:

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

List tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");

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

List<?> tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");

问题是:现在add(..) 方法不再起作用了。
我不能保证该列表仅包含 Strings,因为 aMethodToInitializeTheColumnList() 未在 my 代码中实现。

我的错误是什么?

谢谢!

【问题讨论】:

  • 它在第一个 sn-p 中是如何工作的?缺少new...
  • Abel:函数调用初始化列表。我会添加它以澄清这件事。
  • 修复初始化方法?
  • Tom:它不在我的代码中,请参阅我的编辑。

标签: java generics


【解决方案1】:

来自泛型教程。感谢Michael's answer

添加任意对象是不安全的 但是:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

因为我们不知道元素是什么 c 代表的类型,我们不能添加 反对它。 add() 方法采用 E 类型的参数,元素类型 的集合。当实际 类型参数是?,它代表 一些未知的类型。 我们的任何参数 pass to add 必须是一个子类型 这种未知类型。因为我们不 知道那是什么类型,我们不能通过 任何东西。唯一的例外是 null,它是每个类型的成员。

【讨论】:

  • 原谅我的无知(我不是 Java 人)。如果它不起作用,拥有它的目的是什么?
  • @noloader:目的是这样的:如果你有一个Collection&lt;?&gt;类型的方法参数,你可以传入一个Collection&lt;String&gt;,一个Collection&lt;Integer&gt;或者一个Collection&lt;Whatever&gt;,并且在方法您可以将这些集合的内容作为Object 类型获取。不能向集合中添加任何内容很重要,因为它确保不违反原始类型约束。
【解决方案2】:

您可能想使用List&lt;String&gt; - 这就是泛型的用途,即添加有关集合中对象类型的信息。如果您实际上要拥有一个包含混合类型的列表(这通常是设计不佳的标志),请使用List&lt;Object&gt;

有关使用通配符的更多信息,请查看Generics Tutorial。但它们实际上仅在定义您自己的泛型类或具有泛型参数的方法时才相关。

【讨论】:

  • 感谢您的提示。我不能保证这个列表只包含字符串。
  • 在这种情况下,您可以使用 List 或其他东西,这取决于您知道列表将包含的内容(例如 List
  • 在泛型教程中有解决方案,请参阅我自己的答案。我会考虑接受你的回答,因为你给了我提示。
【解决方案3】:

如果您使用&lt;?&gt;,您的意思是您不会在任何地方使用参数化类型。要么转到特定类型(在您的情况下似乎是List&lt;String&gt;),要么转到非常通用的List&lt;Object&gt;

【讨论】:

  • 我不想指定它,但是为什么正常的add方法会失败呢?
  • 好吧,编译器强制执行语义一致性。你说你不会使用参数化类型,所以它不会让你。 add 方法需要一个类型为泛型参数的参数,因此如果不指定,则不允许使用它。
  • 因为类型是未知。编译无法确定 String 是否合适,因此不允许将 String 添加到列表中。 (实际上,除了null,您不能向该列表添加任何内容。)
【解决方案4】:

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

List<? super String>

因为这个模型完全你所知道的。您说您不确切知道它的类型边界是什么,但是从您的第二行可以公平地假设它必须能够包含字符串。

在我看来,这个编译器比List&lt;Object&gt; 好一点,因为它编码了您对列表中实际内容的不确定性。基本上,您只能向其添加字符串,但当您调用get() 时,返回的元素可以是任何东西(Java 会正确推断此类型为Object)。

实际上,这和List&lt;Object&gt; 之间的唯一区别是后者将允许tmpColumnList.add(3)tmpColumnList.add(new Thread()) 等。我更喜欢它所承载的语义以及实用性。

【讨论】:

    【解决方案5】:

    List&lt;?&gt; 表示列表已(或可能)已键入,但类型未知**。所以添加一些东西可能是错误的**,如果你碰巧不属于这种类型。因为未知,所以警告您。

    您可以使用List&lt;Object&gt;,这意味着可以包含任何类型的列表

    【讨论】:

    • @furtelwart 没错,我的措辞选择不当 :-)。但是这个编译时错误的重点是编译器会发出信号表明代码可能是错误的。顺便说一句,实现的泛型子系统的重点是在编译时搜索代码安全性,并在运行时添加强制转换......
    • 原谅我的无知(我不是 Java 人)。如果它不起作用,拥有它的目的是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多