Java 泛型详解:类型参数的力量

泛型(Generics)是 Java 类型系统的重要支柱。

它让代码更安全、更简洁、更通用,是理解现代 Java 编程的必修课。

本文将系统讲解 Java 泛型的定义、使用、通配符、边界与常见陷阱。


一、为什么需要泛型

在 Java 1.5 之前,集合只能存放 Object 类型:

java 复制代码
List list = new ArrayList();
list.add("Hello");
list.add(123); // 不安全
String s = (String) list.get(0); // 强制类型转换

缺点:类型不安全、容易出错。

Java 1.5 引入 泛型机制(Generics),允许在定义类或方法时引入"类型参数"。

java 复制代码
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123); // 编译错误
String s = list.get(0); // 无需强转

二、泛型的基本语法

java 复制代码
class Box<T> {          // 定义泛型类
    private T value;
    public void set(T value) { this.value = value; }
    public T get() { return value; }
}

Box<Integer> box = new Box<>();
box.set(100);
Integer data = box.get();
关键点 说明
<T> 声明类型参数(Type Parameter)
T 类型变量,可代表任意引用类型
Box<Integer> 实例化泛型类

三、泛型类与泛型接口

泛型类

java 复制代码
class Pair<K, V> {
    private K key;
    private V value;
    public Pair(K key, V value) { this.key = key; this.value = value; }
    public K getKey() { return key; }
    public V getValue() { return value; }
}

泛型接口

java 复制代码
interface Converter<F, T> {
    T convert(F from);
}

class StringToInteger implements Converter<String, Integer> {
    public Integer convert(String from) {
        return Integer.valueOf(from);
    }
}

四、泛型方法

方法也可以定义自己的类型参数:

java 复制代码
public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.println(element);
    }
}

String[] arr = {"A", "B", "C"};
printArray(arr); // 自动推断 T = String

⚡ 泛型方法的类型参数与类的泛型参数独立存在。


五、通配符:? 的三种形态

通配符 ? 表示未知类型,常用于方法参数中。

通配符 含义 示例
? 任意类型 List<?> list
? extends T T 或其子类(上界通配符) List<? extends Number>
? super T T 或其父类(下界通配符) List<? super Integer>

示例:

java 复制代码
public static void show(List<? extends Number> list) {
    for (Number n : list) {
        System.out.println(n);
    }
}
写入能力 读取能力
? extends T ✅ 读安全 ❌ 写
? super T ✅ 写安全 ❌ 读(只能读为 Object)

六、边界与多重限制

java 复制代码
class Calculator<T extends Number & Comparable<T>> {
    public boolean isGreater(T a, T b) {
        return a.compareTo(b) > 0;
    }
}

✅ 可指定多个上界,必须先是类后是接口。


七、泛型数组与类型推断

  • ❌ 泛型数组不能直接创建:new T10(类型擦除原因)
  • ✅ 可使用 List 或 Array.newInstance() 代替。

类型推断:

java 复制代码
List<String> list = List.of("A", "B");
var map = Map.of(1, "A", 2, "B"); // Java 10+

八、泛型的好处与限制

优点 缺点
✅ 编译期类型安全 ❌ 运行时类型擦除
✅ 代码复用性高 ❌ 无法创建泛型数组
✅ 无需强转 ❌ 不能用基本类型

九、常见泛型陷阱

❌ 泛型类型不能用于静态上下文:

java 复制代码
class Box<T> {
    // static T value; // 错误!
}

❌ 泛型类型无法用于 instanceof:

java 复制代码
if (obj instanceof Box<String>) // 错误:类型擦除导致编译不通过

🔚 总结

分类 关键语法 示例
泛型类 <T> class Box<T>
泛型方法 <T> static <T> void print(T t)
通配符 ? extends / ? super List<? super Integer>
边界 T extends Number 限制类型范围
相关推荐
better_liang7 小时前
每日Java面试场景题知识点之-消息队列MQ核心场景与实战
java·面试·kafka·消息队列·rabbitmq·rocketmq·mq
小江的记录本7 小时前
【JVM虚拟机】垃圾回收GC:四种引用类型:强引用、软引用、弱引用、虚引用(附《思维导图》+《面试高频考点清单》)
java·jvm·spring boot·后端·python·spring·面试
小马爱打代码7 小时前
Spring源码 第四篇:Spring 5 源码深度拆解:AOP 全流程核心原理
java·后端·spring
better_liang7 小时前
每日Java面试场景题知识点之-SpringBoot启动流程
java·面试·springboot·源码解析·启动流程
RyFit7 小时前
Java + AI 实战:Spring AI 从入门到企业级落地
java·人工智能·spring
ZhengEnCi9 小时前
01-如何监听接口调用情况?
java·spring boot·后端
JAVA面经实录91710 小时前
MyBatis学习体系
java·mybatis
java1234_小锋10 小时前
在 Spring AI 中如何实现函数调用(Function Calling)?请说明其基本原理和应用场景。
java·人工智能·spring
小马爱打代码10 小时前
Spring源码 第九篇:Spring 5 源码深度拆解 - Spring 事件驱动模型
java·后端·spring
ForgeAI码匠11 小时前
ForgeAdmin|Spring Boot 3 后台框架的自动配置设计:少写配置,多做组合
java·spring boot·后端