泛型在编译期实现类型安全,避免运行时classcastexception;因类型擦除,jvm无法进行运行时泛型校验,故所有类型检查必须由编译器完成。

泛型让 List、Map 这类集合在编译期就“认人”
没泛型时,ArrayList 底层是 Object[],什么都能塞:字符串、数字、自定义对象全混在一起。等你遍历时写 (String) list.get(0),编译器不拦,但运行到那个 Integer 就直接抛 ClassCastException。泛型一加,比如声明成 List<string></string>,编译器立刻盯住:往里 add(123) 直接报错,根本进不了运行时——这不是限制,是提前把隐患掐灭。
为什么不能只靠运行时类型检查?
Java 的类型擦除机制决定了:泛型信息在字节码里被抹掉了,JVM 运行时看不到 <string></string>,只看到裸的 List。所以它没法帮你做运行时校验。反过来,这也说明——**所有类型安全必须靠编译器完成**。一旦漏掉泛型(比如用原始类型 List),等于主动放弃这道防线,后续所有强制转换都变成赌运气。
- 用了
List<string></string>,遍历不用(String)强转,IDE 也能自动补全.length() - 传参给方法时,
process(List<string>)</string>能拒绝List<integer></integer>,避免下游逻辑崩掉 - 反射获取泛型实际类型?得靠
ParameterizedType手动解析,不是自动的
常见踩坑点:原始类型 vs 泛型混用
写 List list = new ArrayList(); 看似省事,实则埋雷。这种“原始类型”(raw type)会绕过全部泛型检查,连 IDE 都可能只给警告不报错。更隐蔽的是泛型通配符误用:
-
List>可读不可写(除了null),别试图add("x") -
List extends Number>只能取值,且只能赋给Number或其父类引用 -
List super Integer>可以add(new Integer(1)),但取出来只是Object
这些规则不是语法糖,是编译器为保类型安全设的硬边界。
立即学习“Java免费学习笔记(深入)”;
泛型不是万能的,擦除机制带来真实限制
因为类型擦除,你不能在运行时判断 list instanceof List<string></string>(语法错误),也不能基于泛型参数做 new T()(得用 Class<t></t> 传入)。如果业务真需要运行时类型信息,比如 JSON 反序列化或通用 DAO,必须配合反射+显式传入 Class<t></t>,否则泛型撑不起全场。
真正关键的不是“用了泛型”,而是“全程不退回到原始类型”。哪怕一个方法签名漏了 <t></t>,或者某处用了 Map 而非 Map<string object></string>,整条类型链的安全性就断了一环。










