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