【问题标题】:Generic list type with question mark [duplicate]带问号的通用列表类型[重复]
【发布时间】:2018-06-28 08:37:07
【问题描述】:

我无法解释/理解 Java 列表的泛型类型:

List<? extends Command> myVar = client.performAction(actionParams);

泛型类型? extends Command 是如何调用的,比如它有名字吗?这种类型究竟是什么?它是Command 对象吗?或者这是否意味着它只接受扩展Command 的类?使用这种结构我有什么优势?这种构造集成在哪个 Java 版本中?

【问题讨论】:

  • 那叫wildcard
  • ?称为通配符运算符。列表 extends Command> 隐含,这个列表只能包含 Command 类型的子类。此外,由于它使用通配符运算符,您的 List, myVar.add() 调用将导致编译错误。
  • 请查看this StackOverflow 问题
  • @akshayapandey List 还暗示该列表只能包含命令或其子类的实例。
  • 非常感谢所有的答案。花了一些时间阅读所有这些。确实,PECS 的帖子已经回答了这个问题,所以我就让它成为答案。

标签: java


【解决方案1】:

Upper-bounded 通配符用于放宽您可以使用的对象的类型限制。在这种情况下,您接受扩展/实现 Command 类型的所有内容。

【讨论】:

  • 不错的答案+1! ;-) 许多人忘记了接口也被考虑在内
【解决方案2】:

关于List&lt;? extends Command&gt; 的重要一点是它是一个抽象 类型。你不能写new List&lt;? extends Command&gt;() 并期望创造一些东西。有两个原因。

  • List 是一个接口,具体实现如ArrayListLinkedList 等。
  • type 参数中的通配符,意思是“这可以是Command 的子类型,包括Command 本身”。

这意味着List&lt;? extends Command&gt; 类型的变量可以引用任何这些具体类型的对象

  • ArrayList&lt;Command&gt;
  • LinkedList&lt;SpecialCommand&gt;
  • CopyOnWriteArrayList&lt;ImportantCommand&gt;

和许多其他组合。当然假设SpecialCommandImportantCommandCommand 的子类型。

当您创建该变量将要引用的对象时,您需要明确说明它是什么具体类型。例如

List<? extends Command> myCommandList = new ArrayList<SpecialCommand>();

一旦你这样做了,当然,你可以在myCommandList上调用一些常用的List方法,比如

Command firstCommand = myCommandList.get(0);

这很好,因为我们知道列表中的任何对象都是Command 的某种类型。但你不能这样做

SpecialCommand mySpecialCommand = new SpecialCommand();
myCommandList.add(mySpecialCommand);

因为编译器无法知道您将正确类型的对象添加到列表中。此时,myCommandList 可能同样是 LinkedList&lt;ImportantCommand&gt; 或类似的,编译器需要阻止向其添加 SpecialCommand

这意味着你应该只使用类型List&lt;? extends Command&gt;,如果你有一个变量在哪里

  • 你不在乎它是什么样的列表(ArrayListLinkedList 或其他)
  • 你不在乎列表中的Command是什么类型
  • 您不会尝试向列表中添加任何内容。

这意味着您通常不会将它用于局部变量或字段。它更有可能是一个方法参数,其中传入的东西可能是LinkedList&lt;ImportantCommand&gt; 或其他任何东西;但您在该方法中所做的只是将对象从列表中取出,并对它们执行Command 类型操作。

自 Java 5 以来,Java 中就有泛型,包括通配符。

【讨论】:

  • ArrayListLinkedList 与这里的泛型有什么关系吗?
  • 不是真的,但它是使它成为 abstract 类型的两个因素之一,而不是您可以实例化的东西。
【解决方案3】:

既然你一次问了很多问题,让我回顾一下:

  • 当您实现要在不同对象上使用的数据结构、容器或算法时,泛型至关重要,而无需重写整个代码
  • 如果我没记错的话,Java 5.0 中引入了泛型, 在 Java 中使用泛型之前,您仍然可以创建包含 Object 对象的灵活数据结构,但您必须将 cast 设置为最终类型并在代码中的很多地方使用 instanceOf。因此引入了泛型来缓解这个问题并简化代码。
  • 正如NiVeR 已经说过的,? 是一个通配符运算符,List&lt;? extends Command&gt; 将限制List 包含扩展或实现类或接口的对象Command 对对象接口实施约束

【讨论】:

    【解决方案4】:

    泛型? extends Command是怎么调用的,比如有没有 给它起什么名字?

    这些被称为通用wildcards

    这种类型到底是什么?是Command 对象吗?

    它仅用于在编译时检查变量分配。在运行时泛型是 erased 并解释为 List myVar = client.performAction(actionParams);

    这是否意味着它只接受扩展Command 的类?

    您只能说List&lt;Command&gt; myVar = client.performAction(actionParams);,它会接受Command 类型或命令子类的任何对象。

    List&lt;? extends Command&gt; myVar 控制变量赋值。因此,您只能将以下泛型分配给myVar。以下赋值都是有效的,假设 SubCommand 扩展了 Command:

    myVar = new ArrayList<SubCommand>
    myVar = new ArrayList<Command>
    

    当用通配符泛型声明集合时,它也可以变成read-only。例如myVar.add(new SubCommand()); 将导致编译器错误。

    使用这种结构对我有什么好处?

    最初 Java 不包括泛型。它是在 Java 5.0 中添加的,以允许对 Java 集合进行类型限制,例如 ListSetMap 等。

    【讨论】:

      【解决方案5】:

      List&lt;? extends Command&gt; 被称为上限通配符(许多答案已经解决了这个问题)。一般来说,没有人会这样宣布他或她的名单;这主要用于方法中(更常见的是静态方法)。

      List&lt;? extends Command&gt; 指的是一个包含一个特定类型的Command(即一个特定的子类)的列表。由于它是未知的子类类型,因此在编译时,您将无法添加任何内容。您的 IDE 可能会将 add 方法解析为 add(null e)

      List&lt;Command&gt; 虽然看起来很相似,但它指的是一个包含任何内容的列表,只要它是 Command(或从 Command 继承的子类)。

      例子:

      List<? extends Command> commands = new ArrayList<FooCommand>();
      commands.add(new FooCommand()); // Not allowed at compile time
      
      List<Command> commands = new ArrayList<>();
      commands.add(new FooCommand());
      commands.add(new BarCommand());
      

      使用时间举例:

      public static void doSomethingToCommands(List<? extends Command> commands) {
          commands.forEach(this::doSomething);
      }
      
      List<FooCommand> fooCommands = getFooCommands();
      doSomethingToComamnds(fooCommands); // Allowed
      
      List<Command> commands = getRandomCommands();
      doSomethingToComamnds(commands); // Not allowed.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-05
        • 1970-01-01
        • 2021-07-09
        • 1970-01-01
        相关资源
        最近更新 更多