编程语言
首页 > 编程语言> > java – Bounded-wildcard相关的编译器错误

java – Bounded-wildcard相关的编译器错误

作者:互联网

我想知道这段代码有什么问题:

Map <? extends String, ? extends Integer> m = null;
Set<Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();

编译器抱怨错误消息:

Type mismatch: cannot convert from Set<Map.Entry<capture#1-of ? extends String,capture#2-of ? extends Integer>> to Set<Map.Entry<? extends String,? extends Integer>>

应该是什么类型的? Eclipse建议Set<?>但我想要比这更具体.

解决方法:

此问题在this old Apache thread中解决:

The problem is that the entrySet() method is returning a
Set<Map.Entry<capture-of ? extends K, capture-of ? extends V>>,
which is incompatible with the type Set<Map.Entry<? extends K, ? extends V>>.
It’s easier to describe why if I drop the extends K and extends V part.
So we have Set<Map.Entry<?, ?> and Set<Map.Entry<capture-of ?, capture-of ?>>.

The first one, Set<Map.Entry<?, ?>> is a set of Map.Entries of different
types – ie it is a heterogeneous collection. It could contain a
Map.Entry<Long, Date> and a Map.Entry<String, ResultSet>> and any other
pair of types, all in the same set.

On the other hand, Set<Map.Entry<capture-of ?, capture-of ?>> is a homogenous
collection of the same (albeit unknown) pair of types. Eg it might be a
Set<Map.Entry<Long, Date>>, so all of the entries in the set MUST be
Map.Entry<Long, Date>.

问题的关键在于顶级通配符capture,这意味着它们本质上是一次性类型参数.相比之下,嵌套通配符不会捕获,并且具有某种不同的含义.

因此,为了简单起见,删除界限,声明

Map<?, ?> m;

表示“某些特定未知类型的键和某些特定未知类型的值的映射”.

但是宣告

Set<Map.Entry<?, ?>> s;

表示“任何类型的键和值的一组条目”.

所以这就是你遇到麻烦的地方,因为表达式m.entrySet()不希望返回它,而是“一些特定未知类型的键和一些特定未知类型的值的一组条目”.并且这些类型是不兼容的,因为泛型aren’t covariant:A Set< Type>不是Set< SuperType>.

(请参阅这篇引人入胜的帖子,这有助于梳理嵌套通配符的细微差别:Multiple wildcards on a generic methods makes Java compiler (and me!) very confused.)

一种解决方法是使用capture helper方法,该方法利用了可以嵌套正式类型参数的事实:

private <K extends String, V extends Integer> void help(final Map<K, V> map) {
    final Set<Map.Entry<K, V>> entries = map.entrySet();
    // logic
}

...

Map<? extends String, ? extends Integer> m = null;
help(m);

这是一个人为的例子,因为String和Integer都是最终的,但它显示了这个概念.

一个更简单的解决方法如下:

Set<? extends Map.Entry<? extends String, ? extends Integer>> s = m.entrySet();

这意味着不允许向s添加非null元素,但是在entrySet返回的Set的情况下,无论如何都不支持add和addAll方法(感谢clarifying this point的newacct).

标签:bounded-wildcard,java,generics
来源: https://codeday.me/bug/20190918/1811337.html