Java 泛型(Generics)是 JDK 5 引入的特性,核心作用是:在编译时检查类型安全,避免运行时类型转换异常,同时让代码更通用、更简洁

简单说:泛型 = 参数化类型,把类型当作参数传递,让类 / 方法 / 接口可以适配多种数据类型。


一、为什么要用泛型?(痛点对比)

1. 没有泛型的代码(不安全、繁琐)

java

运行

List list = new ArrayList();
list.add("Hello");
list.add(100); // 可以存任意类型,很危险

// 取出时必须强转,容易报 ClassCastException
String str = (String) list.get(1); // 运行时报错!

问题:

  • 编译不报错,运行时才抛异常
  • 每次取值都要强制类型转换
  • 集合可以存任意类型,类型不安全

2. 使用泛型的代码(安全、简洁)

java

运行

List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(100); 编译直接报错!类型不匹配

String str = list.get(0); // 无需强转

优势:

  • 编译期类型检查,提前发现错误
  • 自动类型转换,代码更简洁
  • 集合只能存指定类型,类型安全

二、泛型的三种使用形式

1. 泛型类 / 泛型接口

把泛型定义在类 / 接口上,整个类内都可以使用这个泛型类型。

语法

java

运行

class 类名<T> { }
interface 接口名<T> { }
  • <T> 就是类型参数,可以写任意标识(常用 T、E、K、V)
  • 使用时传入具体类型(如 StringInteger
示例:通用泛型类

java

运行

// 泛型类:T 是类型参数,使用时才确定具体类型
public class Box<T> {
    private T data;

    public void set(T data) {
        this.data = data;
    }

    public T get() {
        return data;
    }
}

// 使用
Box<String> stringBox = new Box<>();
stringBox.set("Java");
String s = stringBox.get();

Box<Integer> intBox = new Box<>();
intBox.set(100);
Integer i = intBox.get();

2. 泛型方法

把泛型定义在方法上,方法独立于类拥有自己的类型参数。

语法

java

运行

修饰符 <T> 返回值类型 方法名(参数列表) { }

<T> 必须写在返回值前面

示例:通用泛型方法

java

运行

public class GenericMethod {
    // 泛型方法:打印任意类型的数组
    public static <T> void printArray(T[] array) {
        for (T t : array) {
            System.out.println(t);
        }
    }

    public static void main(String[] args) {
        Integer[] intArr = {1,2,3};
        String[] strArr = {"A","B","C"};
        
        printArray(intArr); // 自动适配 Integer
        printArray(strArr); // 自动适配 String
    }
}

三、泛型常用通配符

1. 无界通配符 <?>

表示任意类型,常用于只读取数据、不修改的场景。

java

运行

public static void printList(List<?> list) {
    for (Object obj : list) {
        System.out.println(obj);
    }
}

✅ 可以接收 List<String>List<Integer> 等任意 List


2. 上界通配符 <? extends 类>

只能接收 该类及其子类(读安全,写不安全)

java

运行

// 只能传入 Number 或其子类(Integer、Double等)
public static void getNum(List<? extends Number> list) { }

3. 下界通配符 <? super 类>

只能接收 该类及其父类(写安全)

java

运行

// 只能传入 Integer 或其父类(Number、Object)
public static void addNum(List<? super Integer> list) {
    list.add(100);
}

四、泛型常用类型参数命名规范

行业通用写法,见名知意:

  • T:Type(任意类型)
  • E:Element(元素,集合常用)
  • K:Key(键)
  • V:Value(值)
  • N:Number(数字)

五、泛型重要特性:类型擦除

Java 泛型是伪泛型,只在编译阶段有效,编译成 class 文件后,泛型信息会被全部删除

示例:

java

运行

List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
// 编译后:两者的 class 完全一样,都是 List
System.out.println(strList.getClass() == intList.getClass()); // true

⚠️ 注意:

  • 不能用基本类型(int/double)作为泛型参数,必须用包装类(Integer/Double
  • 不能创建泛型数组:T[] arr = new T[10]; ❌ 错误

六、泛型的好处总结

  1. 类型安全:编译期检查,避免运行时类型转换异常
  2. 消除强制转换:代码更简洁、可读性更高
  3. 代码复用:一套逻辑适配多种类型,不用重复写代码
  4. 提高性能:避免运行时类型检查
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐