大家好,我尝试扩展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();
...
}
...
}
我收到编译时错误
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
接下来的解决方案可以完成这项工作,但实际上很难看:
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();
...
}
...
}
据我所知,问题是String
中使用的类型变量Iterator<Map.Entry<String,String>>
未扩展String
<声明中使用的Map<? extends String, ? extends String> m
<本身} / p>
答案 0 :(得分:6)
最简单的方法是使用 for-each循环。即使在这种情况下,您也需要使用与给定映射中相同的通配符对Entry进行参数化。原因是Entry<? extends String, ? extends String>
不是Entry<String, String>
的子类型。 String
是final
类的事实在这里是无关紧要的,因为编译器不知道这一点。
for (Entry<? extends String, ? extends String> entry : m.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
如果你真的需要一个Iterator,那么编译的语法有点莫名其妙:
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();
}
我最初期望迭代器只是Iterator<Entry<? extends String, ? extends String>>
类型,它最初看起来是在iterator()
上调用的Set<Entry<? extends String, ? extends String>>
方法的返回类型,它反过来似乎是在[{1}}上调用entrySet()
的返回类型。
然而,它比这复杂一点。我在这里找到了一个可能的答案:
有趣的是:
问题是
Map<? extends String, ? extends String>
方法正在返回aentrySet()
, 这与类型Set<Map.Entry<capture-of ? extends K, capture-of ? extends V>>
不兼容。 如果我放弃Set<Map.Entry<? extends K, ? extends V>>
和extends K
部分,则更容易描述原因。 我们有extends V
和Set<Map.Entry<?, ?>
。第一个,
Set<Map.Entry<capture-of ?, capture-of ?>>
是一组不同的Map.Entries 类型 - 即它是异构集合。它可能包含一个Set<Map.Entry<?, ?>>
和Map.Entry<Long, Date>
以及其他任何内容 一对类型,都在同一组中。另一方面,
Map.Entry<String, ResultSet>>
是同质的 收集相同(虽然未知)的一对类型。例如它可能是一个Set<Map.Entry<capture-of ?, capture-of ?>>
,所以集合中的所有条目必须是Set<Map.Entry<Long, Date>>
。
答案 1 :(得分:4)
通配符有点模糊,有时我们希望将通配符转换为更有形的类型变量。
标准方法是引入具有相应类型变量的方法
public void putAll(Map<? extends String, ? extends String> m)
{
_putAll(m);
}
<S1 extends String, S2 extends String>
void _putAll(Map<S1, S2> m)
{
Iterator<Map.Entry<S1,S2>> iterator = m.entrySet().iterator();
}
在java8中,也可以尝试
public void putAll(Map<? extends String, ? extends String> m)
{
m.forEach( (k,v)->
{
...
});
}
(k,v)的类型被推断为捕获类型,就像(S1,S2)一样。但是,如果我们将其类型修改为(String,String),由于forEach
m.forEach( (String k, String v)->
答案 2 :(得分:1)
为什么不一起避免使用迭代器,因为这段代码似乎适用于putAll
的实现:
for(String s: m.keySet()){
put(s.toLowerCase(), m.get(s));
}
至于为什么你似乎无法解决这个错误,我不知道。我尝试了多种变体,似乎没什么用。
答案 3 :(得分:0)
我的理解是:如果您可以从String
派生,可以说是LeftRightString
和UpDownString
,那么
Map<LeftRightString,LeftRightString>
是Map<? extends String, ? extends String>
Map<String, String>
是Map<? extends String, ? extends String>
Map<LeftRightString,LeftRightString>
不是Map<String,String>
因此你的迭代器类型不匹配。如果它被允许那么,当它不起作用时,以下内容将起作用:
void putAll(Map<? extends String, ? extends String> pm) {
Map<String, String> m = pm;
m.add(new UpDownString(), new UpDownString()); // ooops!! if ? was LeftRightString
}
(更新)我想补充一点,我在这里说的几乎所有内容都在Oracle Java教程中,所以我很困惑为什么这么多人一直在评论这是错误的。可以在Java Specification中找到教程中没有的内容。我没有做的是给出一个解决方法,但其他答案有。