有界通配符相关的编译器错误 [英] Bounded-wildcard related compiler error

查看:95
本文介绍了有界通配符相关的编译器错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  Map< ;?扩展字符串,?扩展Integer> m = null; 
设置< Map.Entry <?扩展字符串,?扩展Integer>> s = m.entrySet();

编译器抱怨错误信息:



< blockquote>

类型不匹配:无法从 Set< Map.Entry< capture#1-of?扩展字符串,捕获#2的?将Integer>> 扩展为 Set< Map.Entry<扩展字符串,?扩展整数>>


s 是? Eclipse建议使用 Set <?>< / code>,但是我想要比这更具体。

解决方案

这个问题在这个旧的Apache线程


问题在于 entrySet )方法返回一个
Set< Map.Entry< capture-of?扩展K,捕获?扩展V>>
,这与 Set< Map.Entry <?类型不兼容。延伸K,?扩展V>>
如果我放弃扩展K 扩展V 部分,为什么要更容易描述。
因此,我们有 Set< Map.Entry<?,?> Set< Map.Entry Set< Map.Entry<?,?>>< / code& ;> 是一组不同
类型的Map.Entries集合,即它是一个异构集合。它可以包含
Map.Entry< Long,Date> 和一个 Map.Entry< String,ResultSet>>

另一方面, Set< Map 和任何其他
类型的对,都在同一个集合中。 .Entry >>
是相同(尽管未知)类型的同类
集合。例如它可能是
Set< Map.Entry< Long,Date>> ,所以集合中的所有条目必须是
Map.Entry< Long,Date>


问题的症结在于顶级通配符 capture >,这意味着它们基本上是一次性类型参数。相反,嵌套通配符不会捕获,并且具有不同的含义。

因此,为了简化,删除边界,声明

 地图<?,?>米; 

表示一些特定未知类型的键的映射, em> 未知类型的值。



但声明

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

表示任何类型的键和值的一组条目。



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

(请参阅这篇引人入胜的文章,它有助于区分嵌套通配符的细微差别:。)



一种解决方法是使用 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();
//逻辑
}

...

地图< ;?扩展字符串,?扩展Integer> m = null;
help(m);

字符串 Integer 都是 final ,但它显示了这个概念。



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

  Set <?扩展Map.Entry <?扩展字符串,?扩展Integer>> s = m.entrySet(); 

这意味着将非 - null 元素添加到 s 是不允许的,但是如果 Set entrySet返回 add addAll 方法不受支持(感谢澄清这一点)。


I am wondering what is wrong with this code:

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

The compiler complains with the error message:

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>>

What should the type of s be? Eclipse suggests Set<?> but I am trying to get more specific than that.

解决方案

This issue is addressed in 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>.

The crux of the problem is that top-level wildcards capture, meaning they are essentially one-off type parameters. In contrast, nested wildcards don't capture, and have somewhat of a different meaning.

So, removing the bounds for simplicity, declaring

Map<?, ?> m;

means "a map of some specific unknown type of keys and some specific unknown type of values".

But declaring

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

means "a set of entries of any type of key and value".

So that's where you run into trouble because the expression m.entrySet() doesn't want to return that but instead "a set of entries of some specific unknown type of keys and some specific unknown type of values". And those types are incompatible because generics aren't covariant: A Set<Type> isn't a Set<SuperType>.

(See this fascinating post, which helps tease apart the nuances of nested wildcards: Multiple wildcards on a generic methods makes Java compiler (and me!) very confused.)

One workaround is to use a capture helper method, which takes advantage of the fact that formal type parameters can be nested:

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);

That's a contrived example since String and Integer are both final, but it shows the concept.

A simpler workaround is the following:

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

This means adding non-null elements to s isn't allowed, but in the case of the Set returned by entrySet, the add and addAll methods are unsupported anyway (thanks to newacct for clarifying this point).

这篇关于有界通配符相关的编译器错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆