Ссылка метода на метод экземпляра из типа класса vs Ссылка метода на метод экземпляра из экземпляра - PullRequest
0 голосов
/ 07 марта 2020

Ссылка метода на метод экземпляра из экземпляра

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

Ссылка метода на метод экземпляра из типа класса

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

почему Consumer<String> c = PrintStream::println не удалось?

Ответы [ 3 ]

2 голосов
/ 07 марта 2020

Ответ на ваш вопрос. PrintStream.println(String) - это метод экземпляра, подразумевающий, что для вызова метода требуется экземпляр.

При этом

Consumer<String> c = PrintStream::println

Java не знает, где найти PrintStream экземпляр для вызова println() при вызове c.accept(String). Код скомпилировался бы, если бы println были static в PrintStream.

Это не та же история с

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

, который уже указал экземпляр, на котором println будет вызван (экземпляр System.out).

Существуют случаи, когда экземпляр, для которого вызывается ссылка на метод, не требуется указывать явно, например (заимствование метода Object для простоты)

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

Компилируется, потому что Java может использовать параметр, переданный в Consumer.accept в качестве цели метода, поэтому String::notify может использоваться для этой цели. Но все не так просто (например, notify void), поэтому важно go через docs / spe c о том, как разрешаются ссылки на методы (это хорошее место для начала: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html).

1 голос
/ 07 марта 2020

Но!

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

Ссылки метода на класс имеют неявный первый параметр экземпляра. Это похоже на Method, у которого первый параметр invoke() метода является экземпляром.

0 голосов
/ 07 марта 2020

Поскольку на метод non-static нельзя ссылаться из контекста static.

Вы можете проверить его в System.java

public static final PrintStream out = null;

out - static Вот почему он компилируется.

Хотя для доступа к println из PrintStream необходимо сначала создать экземпляр PrintStream, а затем вызвать println.

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