繁体   English   中英

泛型实现Map.entrySet()时遇到麻烦

[英]Generics trouble implementing Map.entrySet()

我正在尝试扩展AbstractMap以创建MapTreeNode类(通过键而不是通过索引访问子项的树节点)。

我已经有一种方法可以让一组孩子正常工作:

public class MapTreeNode<K,V> implements Map.Entry<K,V> {
    private Map<K,MapTreeNode<K,V>> children = new HashMap<K,MapTreeNode<K,V>>();
    private Set<MapTreeNode<K,V>> child_set = null;

    public Set<MapTreeNode<K,V>> children() {
        if (child_set == null)
            child_set = new ChildSet();

        return child_set;
    }

    ...

    private final class ChildSet extends AbstractSet<MapTreeNode<K,V>> {
        @Override
        public Iterator<MapTreeNode<K,V>> iterator() {
            return children.values().iterator();
        }

        @Override
        public int size() {
            return MapTreeNode.this.childCount();
        }
        ...
    }

}

我想创建一个节点的地图视图( Map<K,V>child_setchild_set但是我不确定Java的泛型是否可行:

public Map<K,V> asMap() {
    return new AbstractMap<K,V>() {
        @Override
        public Set<Map.Entry<K,V>> entrySet() {
            return child_set; // line 166
        }
    };
}

这当然给

MapTreeNode:166: incompatible types
found   : java.util.Set<MapTreeNode<K,V>>
required: java.util.Set<java.util.MapEntry<K,V>>

有没有办法可以为此重用ChildSet类?

问题出在entrySet()的返回类型上。 它是Set<Map.Entry<K,V>> 如您所知,无论A和B如何关联, Foo<A>Foo<B>都不兼容。

我认为这是API中的设计错误。 entrySet()的返回类型实际上应该是Set<? extends Map.Entry<K,V>> Set<? extends Map.Entry<K,V>> 这是为什么:如果您阅读entrySet()文档 ,它表示可以从Set中读取内容,可以从Set中删除内容(这会导致对基础映射的更改),但是无法将内容添加到Set中。 。 这恰好适合生产者的角色-您无需在其中添加任何内容。 根据PECS规则,应使用extends通配符集合类型。

除非您需要MapTreeNode方法中的特定内容,否则将其视为Map.Entry ,这意味着将child_set声明为

private Set<Map.Entry<K,V>> child_set = null;

由于MapTreeNode扩展了Map.Entry ,所以应该没问题。

到目前为止,这是我迄今为止为避免代码重复所做的最大努力:

private abstract class AbstractChildSet<T extends Map.Entry<K,V>> extends AbstractSet<T> {
    @Override
    public boolean remove(Object o) {
        if (o == null || !(o instanceof Map.Entry)) {
            return false;
        }

        MapTreeNode<K,V> node;
        if (o instanceof MapTreeNode)
            node = (MapTreeNode<K,V>) o;
        else
            node = MapTreeNode.this.child(((Map.Entry<K,V>) o).getKey());

        if (node == null || !isParentOf(node))
            return false;

        node.removeFromParent();
        return true;
    }

    @Override
    public int size() {
        return MapTreeNode.this.childCount();
    }

    @Override
    public void clear() {
        MapTreeNode.this.removeAllChildren();
    }
}

private final class ChildSet extends AbstractChildSet<MapTreeNode<K,V>> {
    @Override       
    public boolean add(MapTreeNode<K,V> node) {
        if (MapTreeNode.this.containsKey(node.getKey()))
            return false;

        MapTreeNode.this.addChild(node);
        return true;
    }

    @Override
    public Iterator<MapTreeNode<K,V>> iterator() {
        return children.values().iterator();
    }
}

private final class EntrySet extends AbstractChildSet<Map.Entry<K,V>> {
    @Override
    public boolean add(Map.Entry<K,V> entry) {
        if (MapTreeNode.this.containsKey(entry.getKey()))
            return false;

        MapTreeNode new_child = new HashMapTreeNode(MapTreeNode.this, entry.getKey(), entry.getValue());

        MapTreeNode.this.addChild(new_child);
        return true;
    }

    @Override
    public Iterator<Map.Entry<K,V>> iterator() {
        return new EntryIterator();
    }
}

据我了解,您已经实施了新课程来接送Entry类型的孩子。 要再次构建地图,我将遍历一组条目并重新构建地图。

不确定我是否像其他人一样在这里提供了帮助,我无法完全阅读该课程还包含的内容。

您为什么不像这样简单地投射它:

public Map<K,V> asMap() {
    return (Map<K,V>) this;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM