泛型的核心作用是避免运行时类型转换异常、减少冗余强转代码、支持同一逻辑适配多种类型;最常用形式如list,解决原始集合取元素需手动强转易抛classcastexception的问题。

直接从“为什么需要泛型”开始学,比死记语法更高效。Java 1.5 引入泛型,核心就三点:避免运行时类型转换异常、减少冗余强转代码、让同一套逻辑适配多种类型。学的时候别一上来就啃通配符或上下界,先抓住最常用、最实在的用法。
先搞懂泛型类怎么用
泛型类是新手接触最多的形式,比如 List<string></string>、Box<integer></integer>。关键不是记住写法,而是理解它解决了什么问题:
- 不加泛型的
List可以存任何对象,但取出来必须手动强转,稍不注意就抛ClassCastException - List
里 add(123) 直接报错,根本进不了运行期 - 定义自己的泛型类时,类型参数(如
<t></t>)不能是基本类型(int不行,得用Integer) - 创建实例时,JDK 7+ 支持钻石操作符
,比如new ArrayList(),编译器能自动推断
再掌握泛型方法的独立性
泛型方法和所在类是否泛型无关,它自己就能决定类型。这是很多初学者卡壳的地方——误以为只有泛型类里才能写泛型方法。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 静态方法想用泛型,必须自己声明类型参数,例如:
public static <t> void print(T item)</t> - 非静态方法可以复用类的泛型参数,也可以另起一套,比如类是
<k v></k>,方法可以是<t> T convert(...)</t> - 泛型方法调用时,类型通常由实参推断,不需要显式写
print<string>("hi")</string>,直接print("hi")就行
理解擦除机制,避开常见坑
Java 泛型是“伪泛型”,只在编译期起作用,运行时类型信息被擦除。这个特性直接影响编码方式:
-
ArrayList<string>.class == ArrayList<integer>.class</integer></string>返回 true —— 因为运行时都是ArrayList - 不能用
if (t instanceof T)判断泛型类型,也不能new T()创建实例(类型已不存在) - 需要运行时类型信息时,得靠传入
Class<t></t>对象,比如public <t> T create(Class<t> clazz)</t></t> - 泛型数组不允许直接创建,
new ArrayList<string>[10]</string>编译失败,要用new ArrayList[10]然后转型(带警告)或改用容器
逐步接触通配符和边界
等上面三块练熟了,再碰 ? extends T 和 ? super T。它们本质是为了解决“子类型集合能否赋值给父类型引用”这类问题:
-
List extends Number>表示“某个 Number 子类型的列表”,可读不可写(除了null) -
List super Integer>表示“某个 Integer 父类型的列表”,可写 Integer,读出来只能当 Object - 没边界限制的
List>几乎只用于工具方法,比如打印任意列表:static void print(List> list) - 不要为了用而用,多数业务代码里,明确写
List<string></string>比List>更清晰、安全
不复杂但容易忽略:泛型不是万能的,它解决的是编译期类型安全,不是运行时多态。真正要灵活处理不同行为,还得靠接口抽象和策略模式。把泛型当成“类型检查的保险丝”,而不是“万能胶水”,学起来反而轻松。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










