[英]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_set
用child_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.