Java泛型类型转换未出现预期错误的技术咨询
为什么你的泛型代码没有触发预期的类型转换错误?
这事儿的核心原因是Java泛型的类型擦除机制——Java的泛型是编译时的语法糖,运行时JVM根本不知道T是什么类型,咱们一步步拆解:
1. 编译时的类型擦除
你的Hat<T>类在编译后,所有的T都会被擦除成它的上限类型(这里你没指定上限,默认是Object)。所以convert方法里的这段代码:
T t = (T) s;
编译后实际变成了:
Object t = (Object) s;
这显然是合法的,因为String本来就是Object的子类,所以这个强制转换在编译时只会抛出一个unchecked警告(如果你开了编译器警告的话能看到),运行时完全不会报错。
2. 为什么调用代码没报错?
当你写:
Hat<Integer> h = new Hat<Integer>(); ArrayList<Integer> iList = h.convert("hello");
编译时编译器会帮你做类型校验,它认为convert返回的是ArrayList<Integer>,所以允许赋值给iList。但运行时,这个ArrayList其实是一个底层存储Object的容器,里面放的是String对象——只是编译器给你“伪装”成了ArrayList<Integer>。
3. 错误什么时候会爆发?
你现在只是把这个列表赋值给了变量,还没碰里面的元素。等你尝试从列表里取出元素并赋值给Integer类型变量时:
Integer num = iList.get(0);
这时候JVM会在运行时做一次隐式的强制转换,尝试把String转成Integer,这时候才会抛出ClassCastException,也就是你预期的错误。
怎么让错误提前被检测到?
如果想在编译时就阻止这种不安全的转换,可以给Hat类传入Class<T>类型的参数,用它来做类型校验和转换:
import java.util.*; public class Hat<T> { private Class<T> type; public Hat(Class<T> type) { this.type = type; } public ArrayList<T> convert(String s) { // 这里会在运行时做严格的类型转换,不兼容直接报错 T t = type.cast(s); ArrayList<T> list = new ArrayList<T>(); list.add(t); return list; } }
这样当你用Hat<Integer>调用convert时,运行时type.cast(s)会直接抛出ClassCastException,不用等到取元素的时候。
内容的提问来源于stack exchange,提问作者Sambo
相关产品推荐
相关产品推荐

