我们说来自
的更改Comparator.comparing
源代码
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
到
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<T, U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
我们有以下课程
class PhysicalObject {
double weight;
public Double getWeight(){
return weight;
}
}
class Car extends PhysicalObject {}
以下statament无法编译
Function<PhysicalObject, Double> weight = p->p.getWeight();
Comparator<Car> c = HypotheticComparators.comparing(weight);
此编译Comparator<Car> c3_1 = HypotheticComparators.comparing(PhysicalObject::getWeight);
据我所知,第一个语句无法编译是因为修改后的比较函数没有有界通配符(? super T
),但为什么第二个语句可以编译而没有任何问题?
答案 0 :(得分:1)
将comparing
定义为:
Comparator<T> comparing(Function<T, U> keyExtractor) // abbreviated
声明:
Comparator<Car> c = comparing(weight);
要求参数为Function<Car, ?>
,但weight
为Function<PhysicalObject, Double>
,因此您会收到编译错误。
然而,在做的时候
Comparator<Car> c3_1 = comparing(PhysicalObject::getWeight);
Function<Car, ?>
方法? apply(Car t)
由超级Double getWeight()
的{{1}}充分实施,因为PhysicalObject
是对该方法的调用。
t->getWeight()
方法引用类似于以下lambda:
PhysicalObject::getWeight
或以下匿名类:
Comparator<Car> c3_1 = comparing((Car t) -> {
PhysicalObject p = t;
return p.getWeight(); // call PhysicalObject::getWeight
});
方法参考中允许从Comparator<Car> c3_1 = comparing(new Function<Car, Double>() {
@Override
public Double apply(Car t) {
PhysicalObject p = t;
return p.getWeight();
}
});
扩展到Car
。
答案 1 :(得分:0)
根据JLS(§18.2.1: Expression Compatibility Constraints),这是由于类型推理章节中精确方法参考的缩减阶段,如下图所示。
基本上,编译器能够推断出,因为Car
扩展PhysicalObject
,它应该能够定义Comparator<Car>
Function<Car, Double>
。
显式传递Function<PhysicalObject, Double>
以创建Comparator<Car>
将无效,因为没有足够的信息可供编译器正确推断。