为何Java泛型类型强制转换未抛异常且无编译警告?
泛型类型转换为何未触发异常与编译器警告?
问题描述
我疑惑下述程序为何能正常运行,尤其是为何未抛出异常(见代码注释)。
public class A { public static <U> U m(String s){ U out=null; try { out = (U) Integer.valueOf(Integer.parseInt(s)); } catch (NumberFormatException e){ System.out.println("ex int "); } if(out==null) try { out = (U) Double.valueOf(Double.parseDouble(s)); } catch (NumberFormatException e){ System.out.println("ex double"); } System.out.println(out.getClass().getName()); return out; } public static void main(String[] args) { String s = new String("10.2"); System.out.println(A.<Integer>m(s)); // 此时编译器难道不该生成警告吗? } }
我理解由于类型擦除,编译后的代码等价于:
Object out = (Object) Double.valueOf(Double.parseDouble(s));
但编译器的职责不就是检测错误的类型转换吗?
原因解析
类型擦除让泛型转换退化为Object转换
Java泛型的类型信息仅在编译期有效,编译后所有泛型参数会被擦除为其上限类型(这里<U>未指定上限,默认是Object)。代码里的(U)强制转换,编译后实际是(Object)转换——Integer、Double都是Object的子类,这个转换本身完全合法,不会触发编译错误或运行时异常。编译器警告需手动开启检查
编译器确实能识别这种“未检查的泛型转换”,但默认编译配置下不会主动提示。只有开启-Xlint:unchecked编译选项时,才会收到类似“unchecked cast: java.lang.Double to U”的警告信息。当前代码未触发异常的特殊场景
你在main方法里直接将返回值传给System.out.println,而println的参数是Object类型——方法返回的Double对象直接被当作Object处理,不需要转换为Integer,因此不会触发ClassCastException。如果改成Integer result = A.<Integer>m(s);,运行时就会立刻抛出类型转换异常,因为此时编译器会在赋值环节插入隐式的(Integer)强制转换。
内容的提问来源于stack exchange,提问作者tomku
相关产品推荐
相关产品推荐

