Java 8中的方法引用是否具有具体类型,如果是,它是什么?

这个问题与另一个问题密切相关。 但是,我觉得这个问题的公认答案并不是那么明确。

那么,Java 8中方法引用的类型是什么? 这里有一个关于如何将方法引用“强制转换”(解除?)到java.util.function.Function演示:

 package java8.lambda; import java.util.function.Function; public class Question { public static final class Greeter { private final String salutation; public Greeter(final String salutation) { this.salutation = salutation; } public String makeGreetingFor(final String name) { return String.format("%s, %s!", salutation, name); } } public static void main(String[] args) { final Greeter helloGreeter = new Greeter("Hello"); identity(helloGreeter::makeGreetingFor) .andThen(g -> "<<>>") .apply("Joe"); //Compilation error: Object is not a function interface // Function // .identity() // .apply(helloGreeter::makeGreetingFor) // .andThen(g -> "<<>>") // .apply("Joe"); Function .<Function>identity() .apply(helloGreeter::makeGreetingFor) .andThen(g -> "<<>>") .apply("Joe"); //Compilation error: Cannot resolve method 'andThen()' // (helloGreeter::makeGreetingFor) // .andThen(g -> "<<>>") // .apply("Joe"); // java.lang.invoke.LambdaMetafactory ??? } private static  Function identity(final Function fun1) { return fun1; } } 

那么,是否有一种不那么痛苦(更直接)的方法将方法引用转换为可以传递的编译/具体类型?

首先,方法引用“是已经有名称的方法的紧凑,易于读取的lambda表达式”(参见Java教程 – 方法参考 )。

所以实际上,你要求的是lambda表达式的类型。 在JLS§15.27.3(Lambda表达式的类型)中清楚地解释了这一点。

简而言之,提到了三种兼容性:

  1. 作业背景
  2. 调用上下文
  3. 投射上下文

lambda表达式或方法引用的类型由编译器推断。 由于现在可以(并且必须)考虑几种上下文,因此Java 8对类型推断进行了大量增强。

lambda表达式的唯一限制是推断类型必须是function接口 。 实际上,相等的lambda表达式可以在其上下文中具有不同的类型。

从JLS,第15.13.2节“方法参考的类型” :

如果T是函数接口类型(第9.8节),并且表达式与从T派生的地面目标类型的函数类型一致,则方法引用表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的。

如果方法引用表达式与目标类型T兼容,则表达式的类型U是从T派生的地面目标类型。

基本上,方法引用的类型是上下文所期望的。 独立于上下文,方法引用实际上没有类型。 没有办法传递“原始”方法引用,然后将其转换为函数或消费者或稍后的任何内容。

方法引用只是使用传递参数作为输入参数的函数的语法糖。 所以,你可以这样分配它们:

 Runnable runnable = System.out::println; Consumer consumer = System.out::println; 

类型是推断的并且取决于上下文。

你的情况:

 Function foo = helloGreeter::makeGreetingFor; 

它等于:

 Function foo = s -> helloGreeter.makeGreetingFor(s); 

如果你只有一个方法引用helloGreeter::makeGreetingFor ,它没有类型。

如果要为方法引用提供类型而不分配它或将其作为参数传递(将其分配给参数),则可以强制转换:

 String greeting = ((Function)helloGreeter::makeGreetingFor) .apply("Joe");