java.util.Map入口集的问题

时间:2011-08-28 03:21:32

标签: java generics collections iterator

我遇到以下代码的奇怪问题。

Map<String, Object> map = new HashMap<String, Object>();

for(Entry<String, Object> entry : map.entrySet()) {
   // 
}

而下面的代码无法编译。

Map map = new HashMap();

for(Entry entry : map.entrySet()) {  // compile error here
   // 
}

任何线索?

2 个答案:

答案 0 :(得分:7)

entrySet方法签名为Set<Map.Entry<K, V>> entrySet(),因此如果您在声明中声明了泛型类型,则只能引用Map.Entry,就像您在第一个示例中所做的那样。在第二种情况下,你使用的是原始类型,因此它基本上是Set<Object> entrySet(),你需要一个强制转换才能工作,例如。

final Map map = new HashMap();

for(final Entry entry : (Set<Entry>)map.entrySet()) {
   // 
}

答案 1 :(得分:5)

Burt有正当理由,Henning在评论中对其进行了扩展。当引用原始类型的成员时,泛型不会发挥 甚至不依赖于类型参数的泛型

作为一个例子,这应该编译得很好......

public class DataHolder<T> {
    public List<T> ts;
    public List<String> strings = new ArrayList<String>();
}

//...
DataHolder holder = new DataHolder();
holder.strings.add(Integer.valueOf(42));

...即使T不需要映射到具体类型,也不知道strings的类型应该是什么。

对于通用成员方法也是如此,这正是您遇到的问题。 entrySet返回原始类型Set,而不是Set<Entry>,即使不需要返回Set<Entry>类型参数也是如此。行为记录在Java Language Specification, section 4.8

  

未继承自的原始类型C的构造函数(第8.8节),实例方法(第8.8节,第9.4节)或非静态字段(第8.3节)M的类型它的超类或超接口是在对应于C的泛型声明中擦除它的类型。原始类型C的静态成员的类型与它对应于C的泛型声明中的类型相同。

这是一个非常“陷入困境”的规则。

另见

Java Class Generics and Method Generics conflicts