根源在于只读方法使用固定泛型(如List)而非上界通配符(List

问题根源:只读方法却用 raw type 或固定泛型,拒收子类集合
常见错误是定义一个处理父类数据的方法,却硬性要求 List<person></person>,导致传入 List<student></student> 直接编译失败。例如:
void processPeople(List<person> people) { ... }</person>
调用 processPeople(students)(其中 students 是 List<student></student>)会报错:“不兼容的类型”。这不是代码写错了,而是 API 类型契约太窄——它本意是“读取人员信息”,却锁死了输入必须是 Person 本身,违背了“Producer Extends”原则。
重构方案:改用 ? extends Person,开放只读入口
把参数从 List<person></person> 改为 List extends Person>,语义立刻清晰:这个方法只从集合中“产出” Person 或其子类实例,因此任何 Person 的子类型集合都合法。
立即学习“Java免费学习笔记(深入)”;
- ✅
processPeople(new ArrayList<student>())</student>—— 允许 - ✅
processPeople(new ArrayList<teacher>())</teacher>—— 允许 - ❌
people.add(new Student())—— 编译拒绝,防止混入不一致类型 - ✅
Person p = people.get(0)—— 安全,取出对象必是Person或其子类
连锁问题:下游写入操作因上游未适配 super 而断裂
如果该方法内部还要把结果转发给另一个收集器,比如:collector.collect(p),而 collector 声明为 Collector<person></person>,同样会卡住。此时不能简单改成 Collector extends Person>(那是只读),而应使用 Collector super Person>。
因为收集器是“消费者”,它需要能接收 Person 及其所有子类——? super Person 表达的就是这个意图。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
典型组合重构:
- 上游只读:
void process(List extends Person> src) - 下游只写:
void collect(Collection super Person> dest) - 通用搬运:
<t> void copy(List extends T> src, Collection super T> dest)</t>
真实踩坑场景:工具类泛型方法被误用为“万能容器”
有开发者写了一个日志打印工具:
public static void logList(List list) { ... }
看似能接收任意 List,实则放弃全部类型检查,运行时强转风险高。更糟的是,后续有人想加校验逻辑:if (item instanceof Student),却发现 item 是 Object,无法直接判断。
重构后应明确意图:
- 若只需打印字符串表示:
logNames(List extends Person> people) - 若需统一存档到基类集合:
archive(List extends Person> src, List<person> archive)</person>→ 进一步升级为List super Person>提升兼容性
不复杂但容易忽略

















