比较器比较类型推断

时间:2018-03-07 22:26:12

标签: java

我们说来自

的更改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),但为什么第二个语句可以编译而没有任何问题?

2 个答案:

答案 0 :(得分:1)

comparing定义为:

Comparator<T> comparing(Function<T, U> keyExtractor) // abbreviated
声明:

Comparator<Car> c = comparing(weight);

要求参数为Function<Car, ?>,但weightFunction<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),这是由于类型推理章节中精确方法参考的缩减阶段,如下图所示。

enter image description here

基本上,编译器能够推断出,因为Car扩展PhysicalObject,它应该能够定义Comparator<Car> Function<Car, Double>

显式传递Function<PhysicalObject, Double>以创建Comparator<Car>将无效,因为没有足够的信息可供编译器正确推断。