【问题标题】:Generics in java wildcardsjava通配符中的泛型
【发布时间】:2017-04-11 14:17:20
【问题描述】:
List<Integer> ints = new ArrayList<Integer>();
 ints.add(1); ints.add(2);
 List<? extends Number> nums = ints;
 nums.add(3.14);   // compile-time error
assertints.toString().equals("[1, 2, 3.14]");

为什么会出现编译时错误?

【问题讨论】:

标签: java


【解决方案1】:

这是因为 java 泛型中的类型擦除。 您不能向列表中添加新元素,因为它的类型参数在编译时未定义。 列表List&lt;? extends Number&gt; nums 表示不能对其调用add方法。

【讨论】:

    【解决方案2】:

    List&lt;? extends Number&gt; 意味着我们不知道列表中的类型是什么,除了它是Number

    在这种情况下,它是List&lt;Integer&gt;。即使您将其分配给List&lt;? extends Number&gt;,它基本上仍然是List&lt;Integer&gt;。而且你不能将 3.14 添加到这样的列表中。

    如果允许,以下代码将是有效的:

    List<Integer> ints = new ArrayList<Integer>();
    ints.add(1); ints.add(2);
    List<? extends Number> nums = ints;
    nums.add(3.14);
    Integer third = ints.get(2);
    

    但是ints.get(2) 不是整数,所以这里会抛出异常。最好在编译时发现这类问题。

    【讨论】:

    • 我认为说nums 仍然是整数列表有点不准确。不仅不能添加浮点数,甚至不能将整数添加到nums 列表。 nums.add(new Integer(1)) 仍然无法编译。
    • 同意@jrook... 在发生错误的地方,编译器只知道numsList&lt;? extends Number&gt;。它不会跟踪可能分配给nums 的内容。因此,基于numsInteger 的列表,您不会得到编译时错误。这种错误可以在运行时被捕获,尽管在这种特殊情况下它可能由于类型擦除而无法捕获。
    【解决方案3】:

    我认为这里的重要部分是实例化 (new ArrayList&lt;Integer&gt;()),它清楚地将 Integer 传递给 List 类。左侧的菱形符号并不重要,只要它兼容即可。由于您稍后将泛型定义为Integer 的上边界,主要是Number 及其子类型,Java 可以接受,因为它仍然可以处理整数。该对象本质上仍然是List&lt;Integer&gt;

    这就像将字符串分配给对象。它将起作用,因为ObjectString 的超类型。这里的List&lt;? extends Number&gt; 有点像List&lt;Integer&gt; 的超类型。 (我知道这里的“超类型”这个词不正确,请随时纠正我。)

    使用泛型的实例化有点像类本身和对象的实例化。其他一些语言,例如Python 使用术语“元类”来表示这种行为。

    【讨论】:

    • 我见过使用“超类”,所以如果“超类”错了,那也没有那么大的错。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多