You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>()); // 不被允许

问题

  1. 为何通过反射传递时,Box<String>能容纳Box<Integer>类型的对象?
  2. 既然可以容纳,为何调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:05:00