? super T 是逆变通配符,表示接受 T 或其任意父类,用于写入场景以提升函数复用性,如 Function 可用于 Stream.map()。

这是为了兼顾类型安全与泛型灵活性而做的经典通配符设计。它不是随便写的,而是让 map 既能接受更宽泛的输入类型,又能保证输出类型明确可推导。
为什么用 ? super T 而不是 T
这叫“逆变(contravariance)”,目的是支持子类函数复用。比如你有一个 Function<object string></object>,它理论上能处理任意对象(包括 String、Integer 等),那它当然也能安全地用于 Stream<string></string> 或 Stream<integer></integer> 的 map 操作。如果写死成 Function<t r></t>,就只能传入恰好是 T 类型的函数,反而限制了复用性。
- 实际效果:你可以把一个
Function<number string></number>传给Stream<integer>.map(...)</integer>,因为Integer是Number的子类,Number是Integer的超类(即? super Integer包含Number) - 编译器会据此做类型检查,确保不会把不兼容的函数塞进去
为什么用 ? extends R 而不是 R
这叫“协变(covariance)”,是为了让函数返回更具体的子类型时仍能通过编译。比如你写 map(s -> s.toUpperCase()),输入是 String,返回也是 String;但如果你用的是 Function<string charsequence></string>,而 String 实现了 CharSequence,那么返回类型其实是 String(CharSequence 的子类),这时 ? extends R 允许这种“更具体”的返回值被接纳。
- 关键点:R 是目标流元素类型,
? extends R表示“返回的东西是 R 或它的某个子类”,不影响下游使用——毕竟子类可以赋值给父类引用 - 这样设计后,lambda 或方法引用无需强制转型,类型推导更自然
泛型参数 <r></r> 的位置意义
<r></r> 写在方法签名最前面,说明它是独立于 Stream 原始类型的全新类型变量。map 不改变原流结构,只是“转换每个元素”,所以必须声明一个新的类型来承载转换结果。这个 R 会参与整个签名的类型约束,比如:
立即学习“Java免费学习笔记(深入)”;
- 输入函数的参数下界是
T的超类(? super T) - 函数返回值上界是
R的子类(? extends R) - 最终返回
Stream<r></r>,类型完全由你传入的函数决定
和 flatMap 的对比更能看清设计意图
flatMap 的 mapper 类型是 Function super T, ? extends Stream extends R>>,多了一层 “Stream 包裹”。map 只做一对一映射,所以它的函数签名更轻量、更直接。这种差异不是随意为之,而是严格对应语义:map 是“每个元素变一个新元素”,flatMap 是“每个元素变零个或多个新元素并摊平”。类型系统正是通过这些细微差别,提前帮你在编译期守住语义边界。


















