JJava 知识库
JAVA INTERVIEW

高频面试题

Java基础进阶约 3 分钟

你们封装统一 RPC 返回对象和分页组件时,泛型是怎么设计的?遇到过类型擦除带来的问题吗?

参考回答约 3 分钟 · 口语表达
先说结论

我会先定目标和容量,再拆核心链路:掌握泛型类、泛型方法、类型擦除以及 extends 和 super 的使用边界

01

我不会直接画架构图,会先确认目标、规模和一致性要求。掌握泛型类、泛型方法、类型擦除以及 extends 和 super 的使用边界。

02

容量有了以后,再把入口、核心处理和数据落点串起来。沿着「声明类型参数 → 编译期类型检查 → 执行类型擦除 → 生成桥接或强转 → 运行期实际调用」观察输入、状态与输出,这些阶段都可以从日志、指标或源码里验证。 声明类型参数 类型参数把容器和算法的输入输出关系写入签名,使错误在编译期暴露,并减少调用处显式强制转换。 编译期类型检查 编译器检查赋值、调用和通配符边界;泛型默认不协变,所以 List<Integer> 不是 List<Number>。 javap -v Signature:观察泛型签名与擦除后描述符。 java.lang.reflect.Type:ParameterizedType、TypeVariable 的运行期元数据。

03

关键参数要从峰值流量和资源上限反推。编译泛型实现并用 javap -c -v 查看 checkcast 与 bridge 方法;再故意通过原始类型制造 heap pollution,记录异常真正发生的位置。

04

正常链路之外,还要设计失败补偿和可验证的恢复流程。工具方法最初声明为 copy(List<Object>, List<Object>),导致 List<Integer> 和 List<Number> 都无法自然调用。把生产者参数改为 List<? extends T>、消费者改为 List<? super T> 后,类型关系由编译器验证,同时保持调用方无需强转。 固定输入和基线 先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「编译告警」为主基线,记录值应满足「-Xlint:unchecked 应为 0」;同时保存 编译告警数量、ClassCastException 分布,使后续变化能够回到同一时间轴比较。

05

最后再讲扩容、成本和方案边界。方案:更适合的场景:主要收益:代价与边界。 具体类型参数 T:输入输出需要保持同一类型关系:签名清晰且可推断:无法表达只读或只写的宽泛边界。 ? extends T:只从参数读取 T:接受 T 的任意子类型容器:不能安全写入非 null 值。 ? super T:需要向参数写入 T:接受 T 的任意父类型容器:读取结果通常只能视为 Object。

方案主链路从目标到落地
01声明类型参数
02编译期类型检查
03执行类型擦除
04生成桥接或强转
05运行期实际调用