在Java Precisely 3rd Ed。中,有以下代码片段:
BiConsumer<Double[], Comparator<Double>> arraySorter = Arrays::<Double>sort;
但是,我注意到,即使在<Double>
after之后::
,方法引用仍然有效(由于的类型参数而有意义BiConsumer
)。
不过,我很困惑是否存在这样的情况下,::<T>
将有必要在方法的参考,如果是这样,一个例子将是非常有益。
我认为Java 10的局部变量类型推断(var name = ...;
)将解决这个难题。代替目标变量类型提供方法引用的类型,右侧需要完全指定类型,这需要::<T>
在方法引用上使用类型参数()。
首先想到了大门...
var arraySorter = Arrays::<Double>sort;
...但是方法引用本身并没有定义类型。它们需要由编译器转换为功能对象,并且即使存在正好一个类型,编译器也不会搜索寻找适当类型的已知功能接口。
接下来的想法是使用方法引用作为方法的参数,该方法基于该方法的参数返回类型。
class Spy {
static <T> Function<T,T> f2(Function<T,T> f) {
return f.andThen(f);
}
static <T> T identity(T t) {
return t;
}
}
使用此方法,我们可以创建传递给方法的方法引用的局部变量:
Function<Double,Double> double_identity = f2(Spy::<Double>identity);
如预期的那样,我们可以删除 ::<Double>
Function<Double,Double> double_identity = f2(Spy::identity);
出乎意料的是,使用局部变量类型推断就可以了。
var double_identity = f2(Spy::identity); // Infers <Object>!
Object obj = null;
double_identity.apply(obj);
但是,当使用方法引用类型覆盖它时,真正的惊喜就来了。
var double_identity = f2(Spy::<Double>identity); // Error: Double != Object
经过一番战斗,我弄清楚了原因。我们必须将类型应用于f2
方法本身:
var double_identity = Spy.<Double>f2(Spy::identity); // Works.
回想起来,这是有道理的。变量的类型通常为外部函数提供上下文。通过将结果分配给Function<Double,Double>
变量,编译器可以推断的类型f2(...)
,然后将该类型传递给参数。在var name = ...
没有显式类型的情况下,只有一个可用的类型是Object
,因此编译器会进行推断Spy.<Object>f2(...)
,然后确定参数类型必须为Function<Object,Object>
。
不幸的是,它似乎没有从内到外进行解析,因此Spy::<Double>identity
不会导致将函数推断为Spy.<Double>f2(...)
,将变量推断为Function<Double,Double>
。也许Java 11?可能会损坏太多,无法正常工作。
但是,它确实终止了我var name = ...;
为解决OP难题而进行的滥用尝试。
非常感谢@Eugene批评了我在Java 10发行之前的尝试。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句