Java泛型下界疑问:func1创建合法却无法赋值给f2?
Java Function泛型赋值问题解析
问题描述
我对此存在困惑(错误出现在f2 = func1的赋值操作处):
- 为何创建func1时未报错?我们调用了Number.shortValue(),但定义的下界是Number?
- 若func1可以这样创建,为何无法将其赋值给f2?
相关代码
Function<? super Number, ? extends String> func1 = obj -> String.valueOf(obj.shortValue()); Function<Integer, String> f2 = func1;
报错信息
Incompatible types. Found: 'java.util.function.Function<capture<? super java.lang.Number>,capture<? extends java.lang.String>>', required: 'java.util.function.Function<java.lang.Integer,java.lang.String>'
问题解答
1. 创建func1时不报错的原因
func1的参数类型声明为? super Number,表示参数可以是Number或它的父类类型。但编译器处理Lambda表达式时,会自动推断出最具体的合法参数类型——这里Lambda体调用了shortValue()方法,只有Number及其子类拥有这个方法,所以obj被推断为Number类型。而Number属于? super Number的覆盖范围(通配符? super Number包含Number本身),因此Lambda与Function<? super Number, ? extends String>的类型完全兼容,不会触发编译错误。
2. 无法将func1赋值给f2的原因
这涉及到Java泛型的不变性以及协变/逆变规则:
Function<T, R>本身是不变类型,即Function<Number, String>和Function<Integer, String>之间不存在子类型关系,不能直接互相赋值。- 对于
func1的类型Function<? super Number, ? extends String>:- 参数部分
? super Number表示它能接受Number或其父类的参数,但f2要求的是能接受Integer参数的函数。虽然Integer是Number的子类,但逆变规则仅允许Function<Integer, String>赋值给Function<? super Integer, String>,反过来并不成立——编译器无法保证func1的参数类型能安全适配Integer的输入要求。 - 返回值部分
? extends String表示它返回String或其子类(虽然String是final类,实际只能是String),但协变规则仅允许Function<..., String>赋值给Function<..., ? extends String>,反过来也不成立。
- 参数部分
综上,func1的带通配符类型与f2的具体类型不兼容,因此无法直接赋值。如果需要兼容,可以将f2的类型改为Function<? super Integer, ? extends String>,或者将func1的类型明确为Function<Number, String>后,通过通配符转换赋值(如Function<? super Integer, String> f2 = func1;)。
内容的提问来源于stack exchange,提问作者Khanna111
相关产品推荐
相关产品推荐

