标准答案
- 编译器插入类型转换,运行时集合通常只知道 List 而不知道 String 参数。
- 可以通过 Class<T>、TypeToken 或显式工厂把运行时类型传入。
- 通配符表达生产和消费边界,`? extends` 通常读取,`? super` 通常写入。
- 泛型数组、重载擦除冲突和原始类型都可能产生类型安全风险。
题目解析
泛型主要在编译期提供类型检查,运行时通常只保留原始容器类型,以兼容旧字节码。因此 List<String> 和 List<Integer> 不能直接用 instanceof 区分,运行时类型需要 Class、TypeToken 或显式 Schema。
强制转换只改变编译器的信任,不会验证集合里每个元素。原始类型会绕过检查并把风险推迟到读取时,跨边界 API 应尽量避免。
PECS 体现生产和消费边界:extends 适合读取,super 适合写入。泛型数组、擦除后的重载冲突和反射绑定都要明确类型安全策略。
常见误区
- 误区:强制转换 List<String> 就认为元素一定是 String。改正:检查来源、使用运行时类型信息或在边界逐项校验。
- 误区:混用原始类型却忽略警告。改正:保留泛型参数,必要时使用受控的 @SuppressWarnings 并说明原因。
- 误区:用 extends 集合写入具体元素。改正:extends 主要读取,写入具体类型时使用 super 或具体泛型。