Java 具有上限的通配符类型变量的迭代器
大家好,我尝试扩展一个Java 具有上限的通配符类型变量的迭代器,java,generics,Java,Generics,大家好,我尝试扩展一个HashMap来强制执行一个“全小写”规则 公共类HttpQueryMap扩展HashMap { ... @凌驾 公共void putAll(不带迭代器的映射) 最简单的方法是使用for each循环。即使在这种情况下,您也需要使用与给定映射中相同的通配符对条目进行参数化。原因是Entry和Set 第一个是同构的 相同(尽管未知)类型对的集合。例如,它可能是 集合,因此集合中的所有条目都必须 Map.Entry 为什么不一起避免使用迭代器,因为这段代码对于实现put
HashMap
来强制执行一个“全小写”规则
公共类HttpQueryMap扩展HashMap
{
...
@凌驾
公共void putAll(不带迭代器的映射)
最简单的方法是使用for each循环。即使在这种情况下,您也需要使用与给定映射中相同的通配符对条目进行参数化。原因是Entry
和Set
第一个是同构的
相同(尽管未知)类型对的集合。例如,它可能是
集合
,因此集合中的所有条目都必须
Map.Entry
为什么不一起避免使用迭代器,因为这段代码对于实现putAll
,似乎效果很好:
for(String s: m.keySet()){
put(s.toLowerCase(), m.get(s));
}
至于为什么你似乎无法解决这个错误,我不知道。我尝试了多种变体,但似乎没有任何效果。我的理解是:如果有可能从字符串
派生,比如称为LeftRightString
和UpDownString
的类,那么
Map
是Map的一个子类型,通配符有点模糊,有时我们想把通配符变成更具体的类型变量
标准方法是引入具有相应类型变量的方法
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();
}
@阿丽娜:不相关。这是对putAll的重写(Map您在这里考虑过组合而不是继承吗?创建一个类,实现Map
的字符串、字符串和包装Map
,将调用委托给底层Map
,并在必要时执行转换,类似于装饰器模式
。如果您愿意,请告诉我,我可以用一个简单的例子来回答。@Keppil:没有合法的String子类这一事实并没有改变编译器将?扩展String
作为类型参数的方式。这正是为什么我觉得重要的是要注意它的无关性:这是一个很容易将注意力从一个有趣的问题转移到whic上的转移h我想看到一个好的答案。@Keppi:换句话说,如果你将问题文本中出现的所有String
替换为Number
,那么同样的问题也存在,并且被问到了同样的问题。问题中的String
根本不重要,更不用说String
是最终结果了。@Keppil:可以定义一种语言,其中非子类在泛型子类型中的行为与子类不同。这实际上非常有用。但Java不是这样一种语言。这就是为什么它不相关。IteratorI我有点希望@Jon Skeet看到这个问题,因为我相信他会知道怎么回事。他哈it’我对泛型相关问题有很好的了解。我已经用一段可编译的代码更新了答案。但是,我不确定我是否理解为什么它必须是这样。对,这就是我还不能解释的:为什么它必须是Iterator@Ryan斯图尔特因为Entry@ApprenticeQueue:我想我同意你的两种说法。但是关系不能解释这一点,因为根据您的逻辑,因为Integer
是Number
的子类型,那么迭代器i1;迭代器i2=i1;
应该是有效的,我们知道情况并非如此。@RyanStewart请参阅这篇精彩的文章,进一步了解嵌套通配符的工作原理:Spot on.?扩展了Foo
表示“我们现在不知道的某个特定的foo子类型”,它不能与简单的foo
自由互换。m.add实际上应该是m.put(new UpDownString(),new UpDownString());
。但是,这并不能回答为什么条目集上的迭代器不能编译的问题。@Natrix,谢谢。但我认为它回答了这个问题,因为Map.entry不是Map的超类型。Entry@Natix:这个问题的字面答案是它不会编译,因为赋值两边的类型不同,而另一边的类型不同右侧不是左侧的子类型。这个答案试图解释为什么它不是子类型。@托曼德森:它只解决了问题的一半:?扩展字符串与String
部分。这是项
参数化。但即使解决了这个问题,迭代器也有问题ode>参数化,目前还没有人能解释。为什么它必须是IteratorYeah我认为它是在这里创造的:这不是一个很有诗意的名字,但如果它对Brian Goetz来说足够好,那么我想它对我来说就足够好了。我把它称为驯服通配符。这个想法是,通过给某个东西起一个名字,你就能控制它-wh我承认我是直接从那里搬来的。
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 (Entry<? extends String, ? extends String> entry : m.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
}
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();
}
for(String s: m.keySet()){
put(s.toLowerCase(), m.get(s));
}
void putAll(Map<? extends String, ? extends String> pm) {
Map<String, String> m = pm;
m.add(new UpDownString(), new UpDownString()); // ooops!! if ? was LeftRightString
}
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();
}
public void putAll(Map<? extends String, ? extends String> m)
{
m.forEach( (k,v)->
{
...
});
}
m.forEach( (String k, String v)->