Java中如何打印编译器为泛型操作推断出的边界类型?
你对三目运算返回类型的推测是正确的,编译器实际推断的类型就是List<? extends Throwable>。以下是两个问题的具体解答:
能不能编写打印编译器推断泛型类型的函数?
Java泛型基于擦除机制实现,运行时泛型参数的类型信息会被擦除,普通的运行时方法无法直接从对象实例中读取到编译期推断的泛型实参,但是有两类可行方案可以拿到结果:
- 编译期方案(更简单,100%准确)
- 用IDE类型提示:Java 10+版本用
var接收表达式的返回结果,鼠标悬浮到var关键字上,IDE会直接显示编译器推断的完整类型。 - 故意触发编译错误:把表达式赋值给明显不匹配的类型,编译器的报错信息会直接给出表达式的实际推断类型,比如编写代码
List<Object> test = (a == 4) ? exceptionList : errorList;,编译时会明确提示类型不兼容,表达式的实际类型为java.util.List<? extends java.lang.Throwable>。 - 自动化场景可以编写注解处理器,在编译阶段解析抽象语法树直接读取表达式的推断类型,不过实现成本较高。
- 用IDE类型提示:Java 10+版本用
- 运行时近似方案
可以利用匿名内部类会保留泛型签名的特性,配合泛型方法捕获类型参数,自己实现类型读取工具,示例代码如下:
注意这个方案的泛型参数本质还是编译器在编译阶段填充到匿名内部类的签名里的,不是运行时从对象实例上读取到的。import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Arrays; import java.util.List; abstract class TypeReference<T> { public Type getType() { ParameterizedType superType = (ParameterizedType) getClass().getGenericSuperclass(); return superType.getActualTypeArguments()[0]; } } public class TypeDemo { public static <T> void showType(T obj, TypeReference<T> typeRef) { System.out.println("推断的泛型类型:" + typeRef.getType().getTypeName()); } public static void main(String[] args) { int a = 4; List<Exception> exceptionList = Arrays.asList(new Exception("344")); List<Error> errorList = Arrays.asList(new Error("44")); // 调用时传入匿名TypeReference实例即可拿到类型 showType((a == 4) ? exceptionList : errorList, new TypeReference<>() {}); } }
如何确认编译器实际推断的泛型类型?
除了上面提到的IDE提示、编译报错的方法外,还可以通过赋值验证反向确认:
- 把该三目表达式赋值给
List<? extends Throwable>类型的变量不会有编译错误 - 赋值给
List<Throwable>、List<Object>、List<Exception>、List<Error>等其他类型都会触发编译错误,即可确认推断类型和你的推测一致。
内容的提问来源于stack exchange,提问作者theutonium.18
相关产品推荐
相关产品推荐

