为什么我会丢失类型信息?

Vog*_*612 5 java generics iterator type-erasure

我发现了地图,原型和泛型有趣的事情.以下代码:

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
}
Run Code Online (Sandbox Code Playgroud)

我收到关于类型不兼容的编译错误,即:"对象无法转换为条目".

为方便起见

entrySet()如果没有变量再次存储它,为什么迭代器会丢失类型信息?

rawtypes不应该影响类型,因此Map.Entry突然是一个对象.还是我弄错了?

Dav*_*idS 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
Run Code Online (Sandbox Code Playgroud)

但是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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,两个for循环都会产生编译错误.

Java语言规范第4.8节中介绍了此行为:

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

  • "但是map.entrySet()返回Set,而不是Set <Map.Entry>." - >这似乎与文档相矛盾,后者明确指出`entrySet()`的返回类型是`Set <Entry>`. (2认同)
  • @Unihedro,如果您在声明中声明了泛型类型,则只能引用`Map.Entry`.通过使用rawtypes,您已经更改了方法契约.泛型类的Javadoc没有提到如果没有给出类型信息它们会返回rawtypes(例如[List.subList](https://docs.oracle.com/javase/7/docs/api/java/util) /List.html#subList(int,%20int)),但这就是它们的设计方式. (2认同)