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