【问题标题】:Whats the use of saying <? extends SomeObject> instead of <SomeObject>说<有什么用?扩展 SomeObject> 而不是 <SomeObject>
【发布时间】:2013-07-23 22:29:07
【问题描述】:

所以我正在查看一些 Java 代码并偶然发现:

List<? extends SomeObject> l;

基本上,这个列表接受所有属于某种 SomeObject 的对象 - SomeObject 本身或其继承者。但是根据多态性,它的继承者也可以看作 SomeObject,所以这也可以:

List<SomeObject> l;

那么,当第二个选项定义明确且几乎相同时,为什么有人会使用第一个选项?

【问题讨论】:

标签: java generics polymorphism


【解决方案1】:

List&lt;? extends SomeObject&gt; l; 不接受new SomeObject() 但是List&lt;SomeObject&gt; l; 可以。

什么也不起作用: List&lt;SomeObject&gt; l = new ArrayList&lt;SubTypeOfSomeObject&gt;()

什么是有效的: List&lt;? extends SomeObject&gt; l = new ArrayList&lt;SubTypeOfSomeObject&gt;()

【讨论】:

    【解决方案2】:
    List<SomeObject> l;
    

    在这你不能说List&lt;SomeObject&gt; l = new ArrayList&lt;SubClassOfSomeObjectClass&gt;;(不允许) 在哪里

    List<? extends SomeObject> l;
    

    你可以说

    List&lt;? extends SomeObject&gt; l = new ArrayList&lt;SubClassOfSomeObject&gt;;(允许)

    但请注意,在List&lt;? extends SomeObject&gt; l = new ArrayList&lt;SubClassOfSomeObject&gt;; 中,您无法将任何内容添加到您的列表 l,因为 ?表示未知类(当然是 null )。

    更新:对于你的问题在评论What could I possibly do with a list if I cannot add anything to it?

    现在考虑一种情况,您必须编写一个函数来打印您的列表,但请注意,它必须只接受一个包含您的 SomeObject 子类的对象的列表。在这种情况下,如上所述,您不能使用

    public void printList(List&lt;SubClassOfSomeObjectClass&gt; someList)

    那你会怎么做?你会做类似的事情

        public void printList(List<? extends SomeObject> someList) {
            for(SomeObject myObj : someList) {
                 //process read operations on  myObj
            }
    

    【讨论】:

    • 您能否澄清两件事:如果我无法向列表添加任何内容,我可以用它做什么? 内部构造函数中声明的类的含义是什么?
    • @OrCyngiser What could I possibly do with a list if I cannot add anything to it? 有时您只想读取/使用某些容器的内容而不修改它。 What is the meaning of the Class stated in the constructor inside &lt;&gt; 不知道你在问什么。简单地说它是泛型类型。更多信息here。如果您询问&lt;&gt;,请查看herehere
    • @OrCyngiser 查看更新后的答案。希望有帮助!还可以查看 Pshemo 在上述评论中提到的链接。它会让你更好地理解。
    • 一个警告:像 SonarQube 这样的代码分析检查器会将返回通用通配符的方法标记为严重的“代码气味”:“​​强烈建议不要使用通配符类型作为返回类型。因为类型推理规则相当复杂,该 API 的用户不太可能知道如何正确使用它。" rules.sonarsource.com/java/RSPEC-1452
    【解决方案3】:

    作为第一个答案,

    List<? extends SomeObject> l;
    

    必须包含继承自SomeObject的Object,而不是一些直接的SomeObject。

    【讨论】:

      【解决方案4】:

      您要阅读的关键链接是http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html,它详细解释了通用通配符。

      List&lt;SomeObject&gt;List&lt;? extends SomeObject&gt; 不同。请注意以下事项

      List<Object> x = new ArrayList<Object>();
      List<String> y = new ArrayList<String>();
      // x = y; Will throw Compilation exception
      List<? extends Object> z = y; //will pass compilation
      

      您可能希望观察到您可以在 x 和 y 列表中添加一个字符串,但是当您编写一个库函数(例如链接中显示的示例中的 printCollection)而不是接受Collection&lt;Object&gt; 在这种情况下,用户无法将他拥有的字符串列表传递给您的方法,如果您接受Collection&lt;? extends Object&gt;,则用户可以传递他的Collection&lt;Apple&gt;, Collection&lt;Orange&gt; 等,而无需显式创建另一个列表。

      【讨论】:

        【解决方案5】:

        X 不能添加到List&lt;Y&gt;,即使X 可以转换为Y

        所以,在第二种情况下,如果允许 List&lt;X&gt; l; 添加 X 的子类,那将破坏类型安全的基本原则

        【讨论】:

          猜你喜欢
          • 2012-08-08
          • 1970-01-01
          • 2011-11-07
          • 2012-02-27
          • 2012-09-30
          相关资源
          最近更新 更多