
本文详解Java泛型中Function
本文详解java泛型中`function super number, ? extends string>`为何能接收`number`类型lambda,却无法安全赋值给`function
在Java泛型中,? super T(下界通配符)常被误解为“可接受T及其所有父类”,但其真实语义是“该类型安全地支持向其传入T或其子类型的实例”——这是函数参数类型的逆变(contravariance)体现。
以示例代码为例:
Function<? super Number, ? extends String> func1 = obj -> String.valueOf(obj.shortValue());
此处右侧lambda实际推导出的函数类型是Function<number string></number>:因为obj在lambda体内被当作Number使用(调用shortValue()),而Number是抽象类,所有数值子类(如Integer、Double)均继承它。编译器确认:只要传入的是Number或其子类实例(如Integer),shortValue()就一定存在。因此,将Function<number string></number>赋值给更宽泛的Function super Number, ? extends String>是合法的——因为Number本身即满足? super Number(Number是自身的超类型),且String自然属于? extends String。
然而,以下赋值会失败:
立即学习“Java免费学习笔记(深入)”;
Function<Integer, String> f2 = func1; // 编译错误!
原因在于类型安全性不可逆:
-
Function super Number, ? extends String>表示:输入可接受Number或其任意父类(如Object),输出是String的某个子类型(可能是String本身); -
Function<integer string></integer>则严格限定:输入只能是Integer(不能是Double或null),输出必须是String(不能是子类)。
二者方向相反:前者对输入更宽松(逆变),后者对输入更严格;前者对输出更宽松(协变),后者对输出更严格。因此,func1可能是一个Function<object string></object>(例如obj -> obj.toString()),它虽能处理Integer,但也能处理String或ArrayList——这显然违反Function<integer string></integer>的契约(只应接受Integer)。编译器拒绝该赋值,正是为了防止运行时ClassCastException或逻辑错误。
✅ 正确做法是显式转换或重构:
// 若确定func1实际仅处理Integer,应直接声明为具体类型
Function<Integer, String> func1Safe = i -> String.valueOf(i.shortValue());
// 或使用辅助方法确保类型安全
Function<Integer, String> safeCast(Function<? super Number, ? extends String> f) {
return (Integer i) -> f.apply(i); // 显式转型,调用方承担责任
}⚠️ 关键总结:
-
Function super T, R>是输入逆变:可安全传入T及其子类,但不能保证只接受T; -
Function<t extends r></t>是输出协变:返回值是R的子类型,但调用方需按R来使用; - 通配符类型用于消费场景(如参数)时增强灵活性,但牺牲了精确赋值能力;
- 函数赋值必须满足:源类型的输入范围 ⊇ 目标类型的输入范围,且源类型的输出范围 ⊆ 目标类型的输出范围。
理解这一点,是写出类型安全、可维护函数式代码的基础。


















