【问题标题】:Upper bounded wildcard, iterator and for-each loop上限通配符、迭代器和 for-each 循环
【发布时间】:2014-12-05 10:04:08
【问题描述】:

我不明白为什么这段代码会编译:

public void test(Collection<? extends Enum> enumCollection) {
    for (Enum e : enumCollection) {
    }
}

而这个没有:

public void test(Collection<? extends Enum> enumCollection) {
    Iterator<Enum> iterator = enumCollection.iterator();
    //Required: Iterator<Java.lang.Enum>
    //Found: Iterator<capture<? extends Java.lang.Enum>>
}

? extends Enum 在所有情况下都应该是Enum 的子类型,那么为什么我会收到迭代器的编译错误以及为什么它可以与 for-each 循环一起使用?

【问题讨论】:

  • 可能出于同样的原因ArrayList&lt;Object&gt; foo = new ArrayList&lt;String&gt;(); 不起作用,而Object bar = new ArrayList&lt;String&gt;().get(0); 可以。
  • 为什么不能使用Collection&lt;Enum&gt; 而不是Collection&lt;? extends Enum&gt;
  • Iterator&lt;Enum&gt; 表示您知道enumCollection 属于Enum 类型,但Collection&lt;? extends Enum&gt; enumCollection 表明enumCollection 也可以是Enum 的子类型。

标签: java generics casting


【解决方案1】:

我经常发现这句格言如果你需要使用?在您的泛型中,您可能做错了什么适用。

这很好用:

public <T extends Enum<T>> void test(Collection<T> enumCollection) {
    for (Enum e : enumCollection) {
    }
    Iterator<T> iterator = enumCollection.iterator();
}

您的问题是您希望泛型像普通代码一样运行,其中ArrayList 也是List。它不是为此而设计的。泛型是为了确保您使用的是相同的类型,而不是只是一些兼容的类型

在您的情况下 - 匹配 ? extends Enum 您可以使用:

    Iterator<?> iterator = enumCollection.iterator();

效果很好。

您的类型不匹配 - 泛型可以确保它们匹配。

请记住,? 并不意味着 我不在乎它是什么类型它意味着 我不想知道它是什么类型。在泛型类型中使用? 然后期望能够使用该类型是愚蠢的。

【讨论】:

  • @tobias_k - 仍然有效! enum MyCustomEnum {A, B;}test(Arrays.asList(MyCustomEnum.values())) 工作正常。
  • 你说得对,打扰了。我猜Enums 在这方面很特别。 +1
  • @tobias_k - 这不是特定于enums。在泛型中,X extends Y 意味着完全,它必须 extend Y Y 不会这样做。然后捕获实际类型(如果您使用?,则不会捕获)。
  • @user2572030 - 因为泛型用于匹配类型完全List&lt;String&gt; 不是 List&lt;Object&gt;,即使 Object o = "Hello" 是有效的 Java。
【解决方案2】:

关于for循环,根据JLS 14.14.2,代码如下:

public void test(Collection<? extends Enum> enumCollection) {
    for (Enum e : enumCollection) {
    }
}

会被翻译成这样的:

public <T extends Enum> void test(Collection<T> enumCollection) {
    for (Iterator<T> iterator = enumCollection.iterator(); iterator.hasNext();) {
        Enum e = (T) iterator.next();
    }
}

编译没有问题。如您所见,您永远不会直接拥有Iterator&lt;Enum&gt;,而是您所说的Iterator 是您集合中元素的类型。

JLS 的相关部分是:

如果 Expression 的类型是某个类型参数 X 的 Iterable 的子类型,那么让 I 为 java.util.Iterator 类型;否则,让我成为原始类型 java.util.Iterator。

Enum 变量中的存储仅针对每个相关的元素进行。

【讨论】:

  • 感谢您指向 JLS。我认为它会说清楚,但它清楚地表明List&lt;? extends Integer&gt; l 被翻译成Iterator&lt;Integer&gt; #i = l.iterator()。这正是我的问题:它被翻译成的代码无法编译。 (我在我的 IDE 中复制了它,删除了 #)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-02
  • 2015-02-08
  • 2011-01-07
  • 2023-02-23
  • 1970-01-01
相关资源
最近更新 更多