迭代java中的泛型hashmap

Max*_*ler 3 java generics iterator hashmap

我在我的抽象类中绘制了这个hashmap,我的意图是用每个延伸绘制的类的每个实例填充它.我像这样初始化地图:

public static HashMap<Integer, ? extends Drawn> drawns = new HashMap();
Run Code Online (Sandbox Code Playgroud)

我试图像这样添加元素到哈希表:

//this code is in the abstract class Drawn()
public void init(){
    idCount++;
    setID(idCount);
    drawns.put(idCount,this); 

  }
Run Code Online (Sandbox Code Playgroud)

然后我尝试迭代这样:

for(<Integer, ? extends Drawn> E : Drawn.drawns.values()) {
  E.draw();
}
Run Code Online (Sandbox Code Playgroud)

迭代器和init()代码都有编译时错误.但是,如果我将类型参数更改为Drawing而不是我可以编译所有内容,但是当我将子类的实例添加到哈希表时,迭代器不会检测到它们.

Jon*_*eet 5

对于"推杆"部分init- 问题是你说它是某种类型的值的地图,其中该类型延伸Drawn,但你不是说它是什么.这意味着你不能合法地输入任何条目.你真的需要将它改为Map<Integer, Drawn>- 并且对于子类来说应该是绝对正确的,并且下面的迭代代码仍然可以.

你无法做你想做的事情的原因是类型系统试图阻止这种问题:

Map<Integer, String> stringMap = new HashMap<Integer, String>();
Map<Integer, ? extends Object> objectMap = stringMap; // This is fine
objectMap.put(10, new Object()); // This *mustn't* be valid...
String value = stringMap.get(10); // Or this would be dangerous
Run Code Online (Sandbox Code Playgroud)

当你从地图中获取一个值时,你只会知道它是一个Drawn引用 - 如果你想使用任何子类特定的方法,你需要转换为正确的类型.如果你想拥有一个可以有多种不同价值的地图,这是不可避免的.

当您只是迭代值时,您可以使用:

for (Drawn drawn : Drawn.drawns.values()) {
    drawn.draw();
}
Run Code Online (Sandbox Code Playgroud)

或者如果您还需要密钥:

// Or Map.Entry<Integer, Drawn> after the earlier change
for (Map.Entry<Integer, ? extends Drawn> entry : Drawn.drawns.entrySet()) {
    // Use entry.getKey() and entry.getValue() here
}
Run Code Online (Sandbox Code Playgroud)