Java为何不对模糊方法调用报错?泛型接口场景解析
问题解答:泛型Service接口的方法调用选择
好问题!让我们一步步拆解这个场景,看看编译器到底选了哪个方法,以及为什么没有出现模糊调用的错误。
先明确两个方法的签名
首先,我们把接口中的两个process方法的签名清晰列出来:
泛型方法:
<R> R process(Function<? super T, ? extends R> function);这是一个独立的泛型方法(带有自己的类型参数
<R>),接受一个Function,允许输入是T的父类型,输出是R的子类型,最终返回R类型。非泛型方法(依赖接口的类型参数
T):T process(UnaryOperator<T> operator);这个方法的参数
UnaryOperator<T>是Function<T, T>的子接口,要求输入和输出必须都是T类型,返回值也是T。
分析调用的Lambda表达式
调用代码中的Lambda是:
sequence -> sequence.subSequence(0, 1)
当Service的实例是Service<CharSequence>时,Lambda的输入sequence类型为CharSequence,而CharSequence.subSequence()方法的返回类型恰好也是CharSequence——也就是说,这个Lambda的输入和输出类型完全一致。
为什么编译器能确定调用哪个方法?
乍一看,两个方法似乎都能匹配这个Lambda:
- 对于第二个方法:Lambda完全符合
UnaryOperator<CharSequence>的要求(输入输出都是CharSequence),显然是可应用的。 - 对于第一个方法:编译器可以推断泛型参数
R为CharSequence,此时Lambda能匹配Function<? super CharSequence, ? extends CharSequence>,所以这个方法也可应用。
但编译器并没有报错,这是因为Java的重载解析规则会优先选择更具体的方法(参考JLS 15.12.2.5):
UnaryOperator<T>是Function<T, T>的子接口,而Function<T, T>是Function<? super T, ? extends T>的子类型(因为T既是? super T的子类型,也是? extends T的子类型)。- 第二个方法的参数类型
UnaryOperator<T>比第一个方法的Function<? super T, ? extends R>更具体:前者是一个明确限定输入输出类型必须一致的函数式接口,后者则是一个允许输入输出类型更灵活的宽泛接口。
因此,编译器会明确选择第二个方法(T process(UnaryOperator<T> operator)),不会触发模糊调用的错误。
内容的提问来源于stack exchange,提问作者HPH
相关产品推荐
相关产品推荐

