具有上限的通配符类型变量的迭代器 [英] Iterator of a wildcard type variable with upper bound
问题描述
大家好,我尝试扩展一个 HashMap< String,String>
来执行一个全部小写规则
public class HttpQueryMap extends HashMap< String,String>
{
...
@Override
public void putAll(Map< ;? extends String,?extends String> m)
{
...
Iterator< Map.Entry< String,String>> iterator = m.entrySet()。iterator();
...
}
...
}
我得到一个编译时错误
不兼容类型
required:Iterator< Entry< String,String> >找到
:Iterator< Entry< CAP#1,CAP#2>>
其中CAP#1,CAP#2是新鲜的类型变量:
CAP#1从捕获?扩展字符串
CAP#2扩展字符串捕获?扩展字符串
下一个解决方法可以完成这项工作,但它确实很难看:
public class HttpQueryMap extends HashMap< String,String>
{
...
@Override
public void putAll(Map< ;? extends String,?extends String> m)
{
...
Map< String,String> m_str = new HashMap< String,String>();
m_str.putAll(m);
Iterator< Map.Entry< String,String>> iterator = m_str.entrySet()。iterator();
...
}
...
}
据我所知,问题在于 最简单的方法是使用 for-each循环。即使在这种情况下,您也需要使用与给定映射中相同的通配符对Entry进行参数化。原因是 Iterator< Map.Entry< String,String>>中使用的类型变量
String
不会扩展 Map< ;?声明中使用的
String
(本身)。扩展字符串,? extends String>没有Iterator
Entry <?扩展字符串,? extends String>
不是条目< String,String>
的子类型。 String
是一个 final
类的事实在这里并不重要,因为编译器不知道这一点。
.getKey();
String value = entry.getValue();
$ / code>
使用Iterator
如果你确实需要一个Iterator,那么编译的语法有点令人费解:
Iterator <?扩展Entry<扩展字符串,? extends String>> iterator =
m.entrySet()。iterator();
while(iterator.hasNext()){
Entry<扩展字符串,? extends String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
}
我原本以为迭代器只能是迭代<条目< ;?扩展字符串,?扩展字符串>>
,它最初看起来是 Set< code> iterator()
方法的返回类型。 ;条目< ;?扩展字符串,?扩展字符串>> ,它依次类似于在 Map< ;?上调用的
。 entrySet()
的返回类型。扩展字符串,? extends String>
然而,它比这更复杂一点。我在这里找到了一个可能的答案:
有趣的部分是这样的:
问题是
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>
。
Hello everybody I try to extend a HashMap<String,String>
to enforce a "all-lowercase" rule
public class HttpQueryMap extends HashMap<String,String>
{
...
@Override
public void putAll(Map<? extends String, ? extends String> m)
{
...
Iterator<Map.Entry<String,String>> iterator = m.entrySet().iterator();
...
}
...
}
I get a compile-time error
incompatible types
required: Iterator<Entry<String,String>>
found: Iterator<Entry<CAP#1,CAP#2>>
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends String from capture of ? extends String
CAP#2 extends String from capture of ? extends String
The next work-around does the job but it is really ugly:
public class HttpQueryMap extends HashMap<String,String>
{
...
@Override
public void putAll(Map<? extends String, ? extends String> m)
{
...
Map<String,String> m_str=new HashMap<String,String>();
m_str.putAll(m);
Iterator<Map.Entry<String,String>> iterator = m_str.entrySet().iterator();
...
}
...
}
As far as I understand the problem is that the type variable String
used in the Iterator<Map.Entry<String,String>>
does not extend String
(itself) used in the declaration of Map<? extends String, ? extends String> m
Without Iterator
The easiest way is to use a for-each loop. Even in this case, you need the parametrize the Entry with the same wildcards as in the given map. The reason is that Entry<? extends String, ? extends String>
is not a subtype of Entry<String, String>
. The fact that String
is a final
class is irrelevant here, because the compiler has no knowledge of that.
for (Entry<? extends String, ? extends String> entry : m.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
With Iterator
If you really need an Iterator, the syntax that does compile is a bit baffling:
Iterator<? extends Entry<? extends String, ? extends String>> iterator =
m.entrySet().iterator();
while (iterator.hasNext()) {
Entry<? extends String, ? extends String> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue();
}
I originally expected the iterator to be only of type Iterator<Entry<? extends String, ? extends String>>
, which at first appears to be the return type of iterator()
method called on a Set<Entry<? extends String, ? extends String>>
which in turns appears to be the return type of entrySet()
called on Map<? extends String, ? extends String>
.
However, it is a bit more complex than that. I've found a probable answer in here:
The interesting part is this:
The problem is that the
entrySet()
method is returning aSet<Map.Entry<capture-of ? extends K, capture-of ? extends V>>
, which is incompatible with the typeSet<Map.Entry<? extends K, ? extends V>>
. It's easier to describe why if I drop theextends K
andextends V
part. So we haveSet<Map.Entry<?, ?>
andSet<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 aMap.Entry<Long, Date>
and aMap.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 aSet<Map.Entry<Long, Date>>
, so all of the entries in the set MUST beMap.Entry<Long, Date>
.
这篇关于具有上限的通配符类型变量的迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!