Java泛型因类型擦除无法直接调用T的方法,需通过Class<T>反射、限定上界接口、Function或MethodHandle等方式补全类型信息;禁止直接转型调用。

Java 泛型本身不保留运行时类型信息(类型擦除),所以不能直接通过泛型参数 T 动态调用具体对象的成员方法。要实现“对泛型对象动态调用其方法”,核心思路是:**把类型信息补回来**——要么靠显式传入 Class<T>,要么靠对象自身提供可反射调用的线索(如接口、方法名+参数类型),或者借助上下文约束(如限定上界)。
用 Class 辅助反射调用
这是最常见也最可控的方式。泛型类型擦除后,JVM 不知道 T 是什么类,但如果你在运行时把 Class<T> 对象传进来,就能用反射安全地获取并调用方法:
- 定义方法时增加
Class<T> clazz参数 - 用
clazz.getDeclaredMethod("methodName", paramTypes...)获取Method - 调用
method.invoke(instance, args...) - 注意处理
IllegalAccessException(加setAccessible(true))、InvocationTargetException等异常
示例:
<T> T invokeMethod(T obj, Class<T> clazz, String methodName, Object... args) throws Exception {Class[] paramTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
Method m = clazz.getDeclaredMethod(methodName, paramTypes);
m.setAccessible(true);
return (T) m.invoke(obj, args);
}
限定泛型上界 + 接口抽象
如果目标方法在多个类型中语义一致,推荐用接口或抽象类统一契约,而不是硬上反射:
立即学习“Java免费学习笔记(深入)”;
- 声明泛型为
<T extends Actionable>,其中Actionable定义了doWork() - 所有实际类型实现该接口,调用时直接
obj.doWork(),无需反射 - 类型安全、性能好、IDE 可提示、编译期检查
这比“泛指对象+动态调用”更符合 Java 设计哲学,应优先考虑。
用 Function 或 MethodHandle 封装调用逻辑
若需复用某类对象的特定方法调用模式,可提前绑定,避免每次反射查找:
- 用
Function<T, R>表达“从 T 中提取某个属性或计算结果”(适合 getter 或无参方法) - 用
MethodHandle(Java 7+)获得更高性能的反射替代,支持参数适配和类型转换 - 例如:
MethodHandles.lookup().findVirtual(clazz, "getName", methodType(String.class))
适用于高频调用场景,但代码稍重,适合框架层封装。
避免踩坑:泛型不能直接转型调用
下面写法是错的:
T obj = ...;obj.someMethod(); // 编译失败,除非 someMethod 在 Object 或上界中声明
原因:编译器只认 T 的上界(默认 Object),不知道具体类型。即使你传的是 String,也不能直接调用 String.length() —— 必须显式转型或通过上述方式补全类型能力。


















