来自 class 类型的实例方法的方法引用 vs 来自实例的实例方法的方法引用

Method reference to instance method from class type vs Method reference to instance method from instance

从实例中引用实例方法的方法

// compile successfully, out is instance, println is instance method
Consumer<String> c = System.out::println; 

方法引用来自 class 类型的实例方法

// compile fail, PrintStream is class type, println is instance method
Consumer<String> c = PrintStream::println; 

为什么 Consumer<String> c = PrintStream::println 失败了?

但是!

BiConsumer<PrintStream, String> c = PrintStream::println; // compiles!

对 class 的方法引用具有实例的隐式第一个参数。这类似于 Methodinvoke() 方法的第一个参数是实例。

答案就在你的问题中。 PrintStream.println(String)是一个实例方法,意味着调用该方法需要一个实例。

有了这个

Consumer<String> c = PrintStream::println

Java在调用c.accept(String)时,不知道去哪里找PrintStream实例调用println()。如果 printlnPrintStream 中的 static,代码将编译。

这与

不同
Consumer<String> c = System.out::println

已经指定了调用println的实例(实例为System.out)。

有些情况下不需要显式指定要调用方法引用的实例,例如(为简单起见借用对象方法)

Consumer<String> c = String::notify; //notify is an instance method

之所以编译是因为 Java 可以使用传递给 Consumer.accept 的参数作为方法的目标,因此 String::notify 可以用于该目的。但事情并没有这么简单(例如,notify 是无效的),所以通过 docs/spec 了解如何解析方法引用很重要(这是一个很好的起点:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html).

因为无法从 static 上下文中引用 non-static 方法。

您可以在System.java

中查看
public static final PrintStream out = null;

outstatic,这就是它正在编译的原因。

同时,为了访问 PrintStreamprintln,您必须先创建 PrintStream 的实例,然后调用 println.

        PrintStream printStream = new PrintStream("File");
        Consumer<String> c = printStream::println;