我发现地图,原型和泛型都会发生一些有趣的事情。以下代码:
static {
Map map = new HashMap ();
Set <Map.Entry> set = map.entrySet ();
for (Map.Entry entry : set) {} // fine
for (Map.Entry entry : map.entrySet()) {} // compilation error
}
我收到有关Type不兼容性的编译错误,即:&#34; Object无法转换为Entry&#34;。
为什么迭代器超过entrySet()
会丢失类型信息,如果没有变量再次存储它?
rawtypes不应该影响类型,以便Map.Entry
突然成为一个Object。或者我错了?
答案 0 :(得分:7)
您的示例使您看起来拥有您从未拥有的类型信息。你写了:
Map map = new HashMap ();
Set <Map.Entry> set = map.entrySet();
for (Map.Entry entry : set) {} // fine
for (Map.Entry entry : map.entrySet()) {} // compilation error
但map.entrySet()
正在返回Set
,而不是Set <Map.Entry>
。您已执行未经检查的作业,该作业会“添加”类型信息。
在第二个for循环中,我们不知道Set
中的内容,因此如果没有显式强制转换,我们就无法迭代Set <Map.Entry>
。
例如,将原始示例与我们未使用未选中的作业“添加”类型信息的示例进行比较。
Map map = new HashMap();
Set set = map.entrySet();
for (Map.Entry entry : set) {
} // Object cannot be cast to Entry
for (Map.Entry entry : map.entrySet()) {
} // Object cannot be cast to Entry
在这种情况下,两个for循环都会产生编译错误。
Java语言规范第4.8节
中记录了此行为构造函数的类型(§8.8),实例方法(§8.8,§9.4),或者 非静态字段(第8.3节)未从中继承的原始类型C的M. 它的超类或超级接口是它的类型的擦除 对应于C的泛型声明。静态成员的类型 原始类型C与泛型声明中的类型相同 对应于C.
答案 1 :(得分:4)
我认为简短的回答是Java在某些情况下允许“未经检查的强制转换”,而在其他情况下则不允许。处理原始类型(没有指定类型的泛型类型)是这些实例之一。
请注意,for (Map.Entry entry : set)
相当于:
Iterator it = set.iterator();
while (it.hasNext())
{
Map.Entry entry = it.next();
}
作业:
Set set = map.entrySet();
是允许的,不会生成任何警告,因为您没有引入任何新类型,但在for
循环it.next()
将返回类型Object
,如果Set <Map.Entry> set = map.entrySet();
,您将收到编译器异常你没有明确的演员就分配它。
作业:
Map.Entry
是允许的,但会因显式类型for
生成“未经检查的强制转换”警告,并且it.next()
循环Map.Entry
将返回类型for(Map.Entry entry : (Set<Map.Entry>) map.entrySet())
,并且分配将工作得很好。
您可以将显式强制转换放在for循环中,如下所示:
{{1}}