Java 泛型(Generics)是 JDK 5 引入的核心特性,本质是参数化类型—— 允许类、接口、方法在定义时声明类型参数,使用时再指定具体类型,既能实现代码复用,又能在编译期检查类型安全,避免手动类型转换(向下转型)的繁琐与 ClassCastException 风险。

一、核心价值
  1. 类型安全:编译期校验类型,杜绝运行时类型转换错误(比如把 String 放入 Integer 集合);
  2. 代码复用:一套泛型代码适配多种类型,无需为不同类型重复编写逻辑;
  3. 可读性提升:代码中明确标注类型意图,无需通过注释说明集合 / 方法处理的类型。
二、核心使用场景
1. 泛型类 / 接口

定义类 / 接口时声明类型参数(用<T>表示,T 为类型占位符,可自定义名称如 E、K、V),使用时指定具体类型。

java

运行

// 泛型类定义(T为类型参数)
public class GenericBox<T> {
    private T content;

    // 泛型方法(与类的类型参数一致)
    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }

    // 测试
    public static void main(String[] args) {
        // 使用时指定String类型
        GenericBox<String> stringBox = new GenericBox<>();
        stringBox.setContent("Java泛型");
        String content = stringBox.getContent(); // 无需强制转换

        // 指定Integer类型
        GenericBox<Integer> intBox = new GenericBox<>();
        intBox.setContent(100);
        Integer num = intBox.getContent();
    }
}

注:泛型接口同理(如List<T>Map<K,V>都是 Java 内置泛型接口)。

2. 泛型方法

方法级别独立声明类型参数(即使所在类不是泛型类),语法:<类型参数> 返回值类型 方法名(参数列表)

java

运行

public class GenericMethodDemo {
    // 泛型方法:T为独立类型参数
    public static <T> T getFirstElement(T[] array) {
        if (array == null || array.length == 0) {
            return null;
        }
        return array[0];
    }

    // 测试
    public static void main(String[] args) {
        String[] strArr = {"a", "b", "c"};
        String firstStr = getFirstElement(strArr); // 自动推断T为String

        Integer[] intArr = {1, 2, 3};
        Integer firstInt = getFirstElement(intArr); // 自动推断T为Integer
    }
}
3. 泛型通配符

解决泛型 “不可变” 问题(比如List<String>不是List<Object>的子类),核心有 3 种通配符:

  • ?:无界通配符,适配任意类型(只能读,不能写,避免类型污染);
  • ? extends T:上界通配符,适配 T 及 T 的子类(只能读 T 类型数据);
  • ? super T:下界通配符,适配 T 及 T 的父类(只能写 T 类型数据)。

示例:

java

运行

// 上界通配符:接收List<Integer>、List<Number>等
public static double sum(List<? extends Number> list) {
    double total = 0;
    for (Number num : list) {
        total += num.doubleValue();
    }
    return total;
}

// 下界通配符:接收List<Integer>、List<Object>等
public static void addInt(List<? super Integer> list) {
    list.add(100); // 可写入Integer类型
}
三、关键注意事项
  1. 泛型擦除:Java 泛型仅存在于编译期,运行时类型参数会被擦除(替换为 Object 或上界类型),因此:
    • 不能用new T()(运行时不知道 T 的具体类型);
    • 不能判断if (obj instanceof List<T>)
    • 不能创建泛型数组(new List<String>[10]非法)。
  2. 基本类型不支持:泛型参数只能是引用类型,需用包装类(如List<Integer>而非List<int>)。
  3. 静态成员与泛型:静态方法 / 变量不能使用类的泛型参数(静态成员属于类,初始化时泛型参数未指定)。
  4. 泛型继承规则GenericBox<String>不是GenericBox<Object>的子类,需用通配符兼容。
四、典型应用场景
  1. 集合框架:ArrayList<T>HashMap<K,V>是泛型最核心的应用;
  2. 自定义工具类:如通用的缓存工具Cache<K,V>、数据转换器Converter<F,T>
  3. 框架开发:Spring 的ParameterizedTypeReference<T>、MyBatis 的Mapper<T>均依赖泛型;
  4. 函数式编程:Supplier<T>Consumer<T>等函数式接口基于泛型实现类型适配。
五、总结

Java 泛型是 “编译期语法糖”,核心是通过参数化类型实现类型安全 + 代码复用,掌握泛型类、泛型方法、通配符三大核心,能大幅提升代码的健壮性与复用性。实际开发中,优先使用泛型替代原始类型(如ListList<String>),结合通配符解决泛型兼容性问题,规避类型转换风险。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐