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>:上界,类型必须是 TT 的子类。

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

上界通配符(读取安全)
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
  • 运行时 list1list2 都是 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)

相关推荐
杨杨杨大侠4 小时前
第3章:实现基础事件总线
java·github·eventbus
杨杨杨大侠4 小时前
第4章:添加注解支持
java·github·eventbus
小苏兮4 小时前
【C++】类与对象(下)
开发语言·c++·学习
咖啡Beans4 小时前
异步处理是企业开发的‘生存之道’!Java8和Spring的异步实现,你必须搞清楚!
java·后端
self_myth5 小时前
[特殊字符] 深入理解操作系统核心特性:从并发到分布式,从单核到多核的全面解析
windows·macos·wpf·harmonyos
间彧5 小时前
Java中T类型详解与实际使用
java
凯子坚持 c5 小时前
C++ 连接 Redis:redis-plus-plus 安装与使用入门指南
java·c++·redis
正在走向自律5 小时前
Ubuntu系统下Python连接国产KingbaseES数据库实现增删改查
开发语言·数据库·python·ubuntu·kingbasees·ksycopg2
草莓熊Lotso5 小时前
PyCharm 从入门到高效:安装教程 + 快捷键速查表
开发语言·ide·经验分享·笔记·其他