我遇到以下代码的奇怪问题。
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
//
}
任何线索?
答案 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的泛型声明中的类型相同。
这是一个非常“陷入困境”的规则。