Java 类型参数 T、R 、 O 、K、V 、E 、? 区别

在 Java 泛型和函数式编程中,T、R 和 O 都是类型参数(Type Parameters) ,它们的主要区别在于命名约定和上下文含义,而不是语言层面的区别。它们可以互换使用,但通常遵循一定的命名习惯以提高代码可读性。


1. 常见泛型参数命名约定

类型参数 典型含义 常见使用场景
T Type(通用类型) 表示任意类型,通常用于输入参数或通用类
R Result(结果类型) 表示函数或方法的返回类型
O Output(输出类型) 类似于 R,表示输出类型
E Element(集合元素类型) 常用于集合类(如 List<E>)
K Key(键类型) 用于 Map<K, V> 的键
V Value(值类型) 用于 Map<K, V> 的值
U 第二个泛型类型 当需要多个泛型参数时使用
? 无界通配符 用于表示未知类型, 在泛型中提供了更灵活的用法,特别是在处理集合类时非常有用

2. T vs R vs O vs ? 的区别

(1) T(Type)

  • 表示输入参数的类型 ,通常用于:

    • 泛型类(如 List<T>)
    • 函数式接口的输入参数(如 Predicate<T>)
  • 示例 :

    java 复制代码
    public class Box<T> {
        private T value;  // T 可以是任何类型
    }

(2) R(Result)

  • 表示返回结果的类型 ,通常用于:

    • 函数式接口的返回值(如 Function<T, R>)
    • 方法返回值的泛型
  • 示例 :

    java 复制代码
    Function<String, Integer> strToLength = s -> s.length();  // T=String, R=Integer

(3) O(Output)

  • 类似于 R,表示输出类型 ,但不如 R 常见

  • 通常用于自定义函数式接口(如 MapFunction<T, O>)

  • 示例 :

    java 复制代码
    @FunctionalInterface
    interface MapFunction<T, O> {
        O map(T input);  // T=输入类型,O=输出类型
    }

(4) ?

? 是 Java 泛型中的通配符(wildcard),用于表示未知类型。它在泛型中提供了更灵活的用法,特别是在处理集合类时非常有用。

4.1基本用法
4.1.1. 无界通配符 <?>

表示可以接受任何类型:

java 复制代码
List<?> list = new ArrayList<String>();  // 可以接受任何泛型类型的List
4.1.2. 上界通配符 <? extends T>

表示类型必须是 T 或其子类:

java 复制代码
List<? extends Number> numbers = new ArrayList<Integer>();  // 可以是Number的任何子类
4.1.3. 下界通配符 <? super T>

表示类型必须是 T 或其父类:

java 复制代码
List<? super Integer> list = new ArrayList<Number>();  // 可以是Integer的任何父类
4.2.使用场景
4.2.1. 读取数据(extends 生产者)
java 复制代码
// 使用上界通配符,只能读取
void printNumbers(List<? extends Number> numbers) {
    for (Number n : numbers) {
        System.out.println(n);
    }
    // numbers.add(1);  // 编译错误,因为不确定具体类型
}
4.2.2. 写入数据(super 消费者)
java 复制代码
// 使用下界通配符,可以写入
void addIntegers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    // Integer i = list.get(0);  // 编译错误,只能获取Object类型
}
4.2.3. 既读又写
java 复制代码
// 不使用通配符,可以读写
void processList(List<Integer> list) {
    list.add(1);
    Integer i = list.get(0);
}
4.3. 重要规则
  1. PECS原则(Producer-Extends, Consumer-Super):

    • 生产者(只读)使用 extends
    • 消费者(只写)使用 super
  2. 通配符不能用于泛型类的实例化:

    java 复制代码
    List<?> list = new ArrayList<?>();  // 编译错误
  3. 通配符不能用于泛型方法的类型参数:

    java 复制代码
    <T> void method(List<T> list) {}  // 正确
    <?> void method(List<?> list) {}   // 编译错误
示例代码
java 复制代码
public class WildcardExample {
    public static void main(String[] args) {
        // 上界通配符示例
        List<Integer> intList = Arrays.asList(1, 2, 3);
        printNumbers(intList);
        
        // 下界通配符示例
        List<Number> numList = new ArrayList<>();
        addIntegers(numList);
        System.out.println(numList);  // 输出 [1, 2]
    }
    
    // 上界通配符 - 只读
    static void printNumbers(List<? extends Number> numbers) {
        numbers.forEach(System.out::println);
    }
    
    // 下界通配符 - 可写
    static void addIntegers(List<? super Integer> list) {
        list.add(1);
        list.add(2);
    }
}

示例对比

接口/类 输入类型 输出类型 说明
Function<T, R> T R Java 标准库
MapFunction<T, O> T O 自定义接口
Predicate<T> T boolean 返回固定类型
Supplier<T> 无 T 无输入,返回 T

相关推荐
Flynn Liang38 分钟前
RAG 评估体系:黄金集、检索指标与 LLM-as-Judge 落地
java·langchain·rag·评估·langchain4j·检索指标
SomeOtherTime43 分钟前
Rust生命周期介绍(AI回答)
开发语言·后端·rust
程序猿打工仔1 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
喵本喵叁肆1 小时前
Rényi 差分隐私:把隐私损失看成一族矩(英文原题:Rényi Differential Privacy (CSF 2017))
开发语言·r语言
SimonKing2 小时前
Workbuddy太占C盘空间了,写个迁移工具迁走10G的数据
java·后端·程序员
Hvitur2 小时前
Java - Lambda
java·开发语言·python
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》DataManager数据管理模块:SQLite持久化存储
开发语言·数据库·c++·sqlite
Evand J2 小时前
【MATLAB例程,PMSM19】永磁同步电机(PMSM)基于多速率无迹卡尔曼滤波(UKF)的转速与转子位置估计。测量缺失、状态预测与恢复性能分析
开发语言·matlab·电机·ekf·卡尔曼·电机滤波
喵了几个咪3 小时前
GoWind Flow 拆解:一个 Go 工作流引擎与它的双模式设计器
开发语言·人工智能·后端·golang
꧁细听勿语情꧂3 小时前
二叉树余题,排序、直接插入排序、希尔排序
c语言·开发语言·数据结构·算法