为什么我会丢失类型信息?
Why am I losing type information?
我发现地图、原始类型和泛型会发生一些有趣的事情。以下代码:
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
}
我收到有关类型不兼容的编译错误,即:"Object cannot be cast to Entry"。
如果没有变量再次存储它,为什么迭代器 entrySet()
会丢失类型信息?
rawtypes 不应该影响类型,所以 Map.Entry
突然变成了一个对象。还是我记错了?
您的示例使您看起来拥有从未有过的类型信息。您写了:
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>
。您执行了一项未经检查的作业,其中 "adds" 类型信息。
在第二个 for 循环中,我们不知道 Set
里面有什么,所以我们不能在没有显式转换的情况下迭代 Set <Map.Entry>
。
例如,将原始示例与我们不使用未经检查的分配 "add" 输入信息的示例进行比较。
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 节中记录了此行为:
The type of a constructor (§8.8), instance method (§8.8, §9.4), or
non-static field (§8.3) M of a raw type C that is not inherited from
its superclasses or superinterfaces is the erasure of its type in the
generic declaration corresponding to C. The type of a static member of
a raw type C is the same as its type in the generic declaration
corresponding to C.
我认为简短的回答是 Java 在某些情况下允许 "unchecked cast" 但在其他情况下不允许。处理原始类型(没有指定类型的通用类型)就是其中之一。
请记住,for (Map.Entry entry : set)
等同于:
Iterator it = set.iterator();
while (it.hasNext())
{
Map.Entry entry = it.next();
}
作业:
Set set = map.entrySet();
是允许的并且不会产生任何警告,因为您没有引入任何新类型,但是在 for
循环中 it.next()
将 return 类型 Object
和如果你在没有显式转换的情况下分配它,你将得到编译器异常。
作业:
Set <Map.Entry> set = map.entrySet();
允许 但会生成 "unchecked cast" 警告,因为显式类型 Map.Entry
并且在 for
循环中 it.next()
将 return 类型 Map.Entry
并且作业会正常工作。
您可以像这样将显式强制转换放在 for 循环中:
for(Map.Entry entry : (Set<Map.Entry>) map.entrySet())
我发现地图、原始类型和泛型会发生一些有趣的事情。以下代码:
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
}
我收到有关类型不兼容的编译错误,即:"Object cannot be cast to Entry"。
如果没有变量再次存储它,为什么迭代器 entrySet()
会丢失类型信息?
rawtypes 不应该影响类型,所以 Map.Entry
突然变成了一个对象。还是我记错了?
您的示例使您看起来拥有从未有过的类型信息。您写了:
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>
。您执行了一项未经检查的作业,其中 "adds" 类型信息。
在第二个 for 循环中,我们不知道 Set
里面有什么,所以我们不能在没有显式转换的情况下迭代 Set <Map.Entry>
。
例如,将原始示例与我们不使用未经检查的分配 "add" 输入信息的示例进行比较。
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 节中记录了此行为:
The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.
我认为简短的回答是 Java 在某些情况下允许 "unchecked cast" 但在其他情况下不允许。处理原始类型(没有指定类型的通用类型)就是其中之一。
请记住,for (Map.Entry entry : set)
等同于:
Iterator it = set.iterator();
while (it.hasNext())
{
Map.Entry entry = it.next();
}
作业:
Set set = map.entrySet();
是允许的并且不会产生任何警告,因为您没有引入任何新类型,但是在 for
循环中 it.next()
将 return 类型 Object
和如果你在没有显式转换的情况下分配它,你将得到编译器异常。
作业:
Set <Map.Entry> set = map.entrySet();
允许 但会生成 "unchecked cast" 警告,因为显式类型 Map.Entry
并且在 for
循环中 it.next()
将 return 类型 Map.Entry
并且作业会正常工作。
您可以像这样将显式强制转换放在 for 循环中:
for(Map.Entry entry : (Set<Map.Entry>) map.entrySet())