Java自定义泛型类与反射的异常行为及相关问题咨询
Java泛型与反射的类型问题解析
自定义泛型类Box<T>
@Component("box") public class Box<T> { private T t; // T stands for "Type" public void set(T t) { this.t = t; } public T get() { return t; } @Override public String toString() { return "Box{" + "t=" + t + '}'; } }
服务类TempService
@Component("compo") public class TempService { public Box<String> boxMeth(Box<String> stringBox) { System.out.println(Objects.nonNull(stringBox)); System.out.println("Inside boxMeth!!!!!!"); //System.out.println(stringBox.get()); return stringBox; } }
主函数反射调用代码
TempService tmp = (TempService)apcon.getBean("compo"); tmp.testMethod("1"); Box<Integer> box = (Box)apcon.getBean("box"); box.set(10); Class classObj = tmp.getClass(); Object obj = classObj.getDeclaredConstructor().newInstance(); Method postHookMethod = obj.getClass().getMethod("boxMeth", Box.class); postHookMethod.invoke(obj, box); // 因反射的强制操作被允许 //tmp.testMethod(new Box<Integer>()); // 不被允许
问题
- 为何通过反射传递时,
Box<String>能容纳Box<Integer>类型的对象? - 既然可以容纳,为何调用
stringBox.get()会抛出异常?
回答
问题1的原因
Java泛型是编译期语法糖,编译完成后泛型类型信息会被彻底擦除,所有Box<T>在运行时都会退化为原始类型Box。
编译期的类型校验只是为了保障代码的类型安全,但反射是直接在运行时操作类和方法,完全绕过了编译期的类型检查逻辑。boxMeth方法在运行时的参数类型实际是原始类型Box,而Box<Integer>和Box<String>在运行时本质都是Box类型,所以反射调用时可以正常传递Box<Integer>实例,不会被拦截。
问题2的原因
虽然运行时Box<String>和Box<Integer>都是Box,但调用stringBox.get()时,编译器会在字节码中自动插入类型强制转换逻辑:因为方法声明中stringBox是Box<String>,所以get()的返回值会被自动转成String类型。但实际这个Box内部存储的是Integer对象,运行时把Integer强制转换为String就会触发ClassCastException异常。
如果不调用get(),仅执行不涉及泛型类型的操作(比如判断非空、打印对象本身),就不会触发这个隐式的类型转换,自然不会抛出异常。
内容的提问来源于stack exchange,提问作者SUVAM ROY
相关产品推荐
相关产品推荐

