java--泛型

1. 什么是泛型

  • 泛型(Generic) :JDK 1.5 引入的特性,本质是 参数化类型(Parameterized Type),即把数据类型作为参数传递给类、接口或方法。

  • 解决的问题 :在编译期约束和检查类型,避免运行时的 ClassCastException,同时提高代码复用性。

👉 没有泛型前:

java 复制代码
List list = new ArrayList();
list.add("Hello");
list.add(123); // 不小心加了一个整数

String s = (String) list.get(1); // 运行时才抛出 ClassCastException

👉 使用泛型后:

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

2. 泛型的核心好处

  1. 类型安全:在编译期检查类型。

  2. 避免强制类型转换:减少冗余代码。

  3. 代码复用:同一份代码可作用于不同的数据类型。


3. 泛型的使用场景

泛型主要可以用在 类、接口、方法 上。

3.1 泛型类

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

// 使用
Box<String> box1 = new Box<>();
box1.set("Hello");
String str = box1.get();

Box<Integer> box2 = new Box<>();
box2.set(100);
Integer num = box2.get();
  • T 是一个占位符,实际使用时由具体类型替换。

3.2 泛型接口

java 复制代码
// 泛型接口
public interface Generator<T> {
    T next();
}

// 实现方式一:指定类型
class StringGenerator implements Generator<String> {
    @Override
    public String next() {
        return "Hello";
    }
}

// 实现方式二:继续保持泛型
class GenericGenerator<T> implements Generator<T> {
    private T value;
    public GenericGenerator(T value) { this.value = value; }
    @Override
    public T next() { return value; }
}

3.3 泛型方法

java 复制代码
public class GenericMethodDemo {
    // 泛型方法(返回值前加 <T> 表示这是一个泛型方法)
    public static <T> void printArray(T[] array) {
        for (T item : array) {
            System.out.println(item);
        }
    }
}

// 使用
String[] strs = {"A", "B", "C"};
GenericMethodDemo.printArray(strs);

Integer[] nums = {1, 2, 3};
GenericMethodDemo.printArray(nums);

4. 泛型的通配符(Wildcard)

通配符 ? 表示 未知类型,主要用于增强泛型的灵活性。

4.1 无界通配符 ?

java 复制代码
public void printList(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
}
  • List<?> 可以接收任何泛型类型的 List。

4.2 有界通配符

  • <? extends T>:上界,类型必须是 T 或 T 的子类。

  • <? super T>:下界,类型必须是 T 或 T 的父类。

上界通配符(读取安全)
java 复制代码
public void readList(List<? extends Number> list) {
    Number num = list.get(0); // 安全
    // list.add(10); // 编译错误:不能保证类型
}
下界通配符(写入安全)
java 复制代码
public void writeList(List<? super Integer> list) {
    list.add(10); // 可以写入 Integer 或其子类
    Object obj = list.get(0); // 读取时只能作为 Object
}

💡 口诀:

  • 生产者用 extends,消费者用 super(PECS 原则)。

5. 泛型的类型擦除

Java 的泛型只在 编译期有效 ,运行时会进行 类型擦除,即替换为原始类型(Raw Type)。

java 复制代码
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();

System.out.println(list1.getClass() == list2.getClass()); // true
  • 运行时 list1 和 list2 都是 ArrayList。

  • 泛型信息会在编译后擦除,因此不会生成多个类。


6. 泛型与数组的区别

  • 数组是协变的 :Integer[] 可以赋值给 Number[]。

  • 泛型是不可变的 :List<Integer> 不能赋值给 List<Number>。

java 复制代码
Number[] nums = new Integer[10]; // 合法
// List<Number> list = new ArrayList<Integer>(); // 编译错误

7. 泛型的限制

  1. 不能使用基本类型 :List<int> 错误,只能用包装类 List<Integer>。

  2. 不能创建泛型数组 :new T[10] 错误。

  3. 静态变量不能使用类型参数。

  4. 类型擦除后不能区分方法重载。


8. 常见应用

  1. 集合框架 :List<E>, Map<K,V>。

  2. 工具类 :Collections.sort(List<T> list)。

  3. 自定义泛型工具:

java 复制代码
public 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; }
}

9. 小结

  • 泛型本质:编译期的类型安全检查 + 类型擦除。

  • 核心用法:泛型类、泛型接口、泛型方法。

  • 灵活性工具:通配符(?、extends、super)。

  • 限制:不能直接使用基本类型,数组和泛型有区别,运行时会类型擦除。

  • 原则:生产者 extends,消费者 super (PECS)。

相关推荐
Vex2une7 小时前
Windows 性能监视器发展史:从 PerfMon 计数器到 XPerf 深度诊断
windows·wpa·etw·性能监视器·perfmon·性能计数器·xperf
在角落发呆7 小时前
工具配置备份步骤:从手动备份到自动化方案
运维·windows·自动化
Sarvartha7 小时前
final 关键字
java·开发语言
2601_952047797 小时前
单一策略深度教程:用轻易云把集成任务的报错实时推送到钉钉机器人
java·机器人·钉钉
程序员Sunday7 小时前
JavaScript 事件循环面试题,宏任务与微任务怎么执行|Sunday面试指南
开发语言·javascript·面试·校招·事件循环·程序员sunday
数据狐(Datafox)8 小时前
淘宝图片搜索 API 落地实战:基于以图搜货搭建跨境电商选品系统
java·大数据·微服务
Vd7H20A78 小时前
Windows 下用 llama.cpp 运行 Qwen3.8-27B 并开启 512K 上下文 完全指南
windows·llama
zhangzeyuaaa8 小时前
Ruby 多线程、GVL(GIL)与 Mutex 完全指南
开发语言·前端·ruby