为什么声明是这样的:
default <U extends Comparable<? super U>> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor)
我明白了大部分。 U
是有道理的可以是任何东西,只要它可以与自身的父类(super class)相比较,因此也可以与自身相比较。但我不明白这部分:
Function<? super T, ? extends U>
为什么不直接拥有:Function<? super T, U>
U 不能只是参数化为 keyExtractor 返回的任何内容,并且仍然扩展 Comparable<? super U>
都一样吗?
最佳答案
为什么是这样? extends U
而不是 U
?
因为代码约定。退房 @deduper's answer一个很好的解释。
有什么实际区别吗?
正常编写代码时,编译器会推断出正确的 T
对于诸如 Supplier<T>
之类的事情和 Function<?, T>
,所以没有实际的理由写 Supplier<? extends T>
或 Function<?, ? extends T>
在开发 API 时。
但是如果我们指定类型 会发生什么手动 ?
void test() {
Supplier<Integer> supplier = () -> 0;
this.strict(supplier); // OK (1)
this.fluent(supplier); // OK
this.<Number>strict(supplier); // compile error (2)
this.<Number>fluent(supplier); // OK (3)
}
<T> void strict(Supplier<T>) {}
<T> void fluent(Supplier<? extends T>) {}
strict()
无需显式声明即可正常工作,因为 T
被推断为 Integer
匹配局部变量的泛型类型。Supplier<Integer>
时它会中断如 Supplier<Number>
因为 Integer
和 Number
不是 兼容。fluent()
因为 ? extends Number
和 Integer
是 兼容。在实践中,只有当您有多个泛型类型时才会发生这种情况,需要明确指定其中一个并错误地获取另一个(
Supplier
一个),例如:void test() {
Supplier<Integer> supplier = () -> 0;
// If one wants to specify T, then they are forced to specify U as well:
System.out.println(this.<List<?>, Number> supplier);
// And if U happens to be incorrent, then the code won't compile.
}
<T, U> T method(Supplier<U> supplier);
示例与 Comparator
(原答案)考虑以下
Comparator.comparing
方法签名:public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, U> keyExtractor
)
这里还有一些测试类层次结构:class A implements Comparable<A> {
public int compareTo(A object) { return 0; }
}
class B extends A { }
现在让我们试试这个:Function<Object, B> keyExtractor = null;
Comparator.<Object, A>comparing(keyExtractor); // compile error
error: incompatible types: Function<Object,B> cannot be converted to Function<? super Object,A>
关于Java thenComparing通配符签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63607274/