取消选中强制转换为实现Map <String,V>的泛型类

blu*_*edd 14 java generics casting type-safety unchecked-cast

我试图理解为什么这段代码有一个未经检查的强制警告.前两个演员没有警告,但第三个演员:

class StringMap<V> extends HashMap<String, V> {
}

class StringToIntegerMap extends HashMap<String, Integer> {
}

Map<?, ?> map1 = new StringToIntegerMap();
if (map1 instanceof StringToIntegerMap) {
    StringToIntegerMap stringMap1 = (StringToIntegerMap)map1; //no unchecked cast warning
}

Map<String, Integer> map2 = new StringMap<>();
if (map2 instanceof StringMap) {
    StringMap<Integer> stringMap2 = (StringMap<Integer>)map2; //no unchecked cast warning
}

Map<?, Integer> map3 = new StringMap<>();
if (map3 instanceof StringMap) {
    StringMap<Integer> stringMap3 = (StringMap<Integer>)map3; //unchecked cast warning
}
Run Code Online (Sandbox Code Playgroud)

这是stringMap3演员阵容的完整警告:

类型安全:未经检查强制Map<capture#3-of ?,Integer>转换为StringMap<Integer>

但是,StringMap类声明指定Map(即,String)的第一个类型参数,并且两者map3和转换StringMap<Integer>使用相同类型的第二个类型参数Map(即,Integer).从我的理解,只要演员不扔ClassCastException(并且它不应该因为有instanceof检查),stringMap3将是有效的Map<String, Integer>.

这是Java编译器的限制吗?或者是否有一种情况,ClassCastException如果忽略警告,使用某些参数调用map3或stringMap3的方法可能会导致意外?

Hoo*_*pje 8

行为是指定的.在Java语言规范第5.5.2节中,未经检查的强制转换定义为:

除非至少满足下列条件之一,否则将取消选中从类型S到参数化类型T的强制转换:

  • S <: T

  • 所有类型参数T都是无界通配符

  • T <: SS不具有亚型X比其它T地方的类型参数X没有在的类型参数包含T.

(其中A <: B表示:" A是"的子类型B").

在第一个示例中,目标类型没有通配符(因此它们都是无界的).在你的第二个例子中,StringMap<Integer>实际上是一个子类型Map<String, Integer>(并且没有X第三个条件中提到的子类型).

但是,在你的第三个例子中,你有一个来自Map<?, Integer>to的转换StringMap<Integer>,并且由于通配符?,它们都不是另一个的子类型.此外,显然,并非所有类型参数都是无界通配符,因此没有条件适用:它是未经检查的异常.

如果代码中出现未经检查的强制转换,则需要符合标准的Java编译器发出警告.

像你一样,我没有看到演员阵容无效的任何情况,所以你可以说它是Java编译器的限制,但至少它是一个指定的限制.