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)

相关推荐
计算机软件程序设计3 小时前
基于Python的二手车价格数据分析与预测系统的设计与实现
开发语言·python·数据分析·预测系统
微笑尅乐3 小时前
力扣350.两个数组的交集II
java·算法·leetcode·动态规划
rzjslSe3 小时前
【JavaGuide学习笔记】理解并发(Concurrency)与并行(Parallelism)的区别
java·笔记·学习
青柠编程4 小时前
基于Spring Boot的竞赛管理系统架构设计
java·spring boot·后端
꒰ঌ 安卓开发໒꒱4 小时前
Java面试-并发面试(二)
java·开发语言·面试
Mr.Aholic4 小时前
Java系列知识之 ~ Spring 与 Spring Boot 常用注解对比说明
java·spring boot·spring
比特森林探险记5 小时前
Golang面试-Channel
服务器·开发语言·golang
xiangzhihong85 小时前
Spring Boot实现文字转语音功能
开发语言·python
月夕·花晨5 小时前
Gateway-断言
java·开发语言·分布式·spring cloud·微服务·nacos·sentinel
西贝爱学习5 小时前
【JDK 11 安装包免费下载 免登录Oracle 】jdk11与jdk8有什么区别?
java·开发语言