迭代地图输入集

Ser*_*gio 16 java generics loops map entryset

我需要遍历地图的入口集,我不知道它的参数化类型.

迭代这样的入口集时,为什么不编译?

public void myMethod(Map anyMap) {
    for(Entry entry : anyMap.entrySet()) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这个编译:

public void myMethod(Map anyMap) {
    Set<Entry> entries = anyMap.entrySet();
    for(Entry entry : entries) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这也编译(我不能使用这个,因为我不知道地图的类型):

public void myMethod(Map<String, String> stringMap) {
    for(Entry<String,String> entry : stringMap.entrySet()) {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Dav*_*der 23

你在第一个错误中得到的错误是:

Type mismatch: cannot convert from element type Object to Map.Entry
Run Code Online (Sandbox Code Playgroud)

这是因为编译器会转换FOR-IN循环:

for (Entry entry : anyMap.entrySet()) {
}
Run Code Online (Sandbox Code Playgroud)

至:

for (Iterator i = anyMap.entrySet().iterator(); i.hasNext();) {
    Entry e = i.next(); // not allowed
}
Run Code Online (Sandbox Code Playgroud)

你的第二个例子有效,但只能通过作弊! 你正在做一个未经检查的演员以Set 重新进入Set<Entry>.

Set<Entry> entries = anyMap.entrySet(); // you get a compiler warning here
for (Entry entry : entries) {
}
Run Code Online (Sandbox Code Playgroud)

变为:

Set<Entry> entries = anyMap.entrySet();
for (Iterator<Entry> i = entries.iterator(); i.hasNext(); ) {
    Entry e = (Entry) i.next(); // allowed
}
Run Code Online (Sandbox Code Playgroud)

更新

正如评论中所提到的,两个示例中的类型信息都会丢失:因为编译器的原始类型擦除规则.

为了提供向后兼容性,原始类型实例的所有方法都被其已擦除的对应项替换.所以,因为你Map是一个原始类型,它都会被删除.包括其Set<Map.Entry<K, V>> entrySet();方法:您的原始类型实例将被强制使用已擦除的版本:Set entrySet().


Pol*_*ome 6

这是因为你使用原始类型Map,因此map.entrySet()会获得一个非参数化的Set,它反过来在迭代时产生Object,而不是Entry.

一个简单但优雅的解决方案是使用Map <?,?>,它仍然允许您传递任何Map,但另一方面强制map.entrySet()具有Set <Entry>的返回值:

public void test(Map<?,?> map) {        
    for(Entry e : map.entrySet()){
        Object key = e.getKey();
        Object value = e.getValue();
    }       
}
Run Code Online (Sandbox Code Playgroud)