Использование ссылок на методы в экземпляре, который будет определен во время выполнения в Java

Я проверял правила использования ссылок на методы, но написанный мной код не компилировался. Компилятор постоянно говорит мне, что я не могу ссылаться на нестатический метод из статического контекста. Однако в Java-документах прямо написано, что можно использовать "::" для "ссылки на метод экземпляра произвольного объекта определенного типа". Кто-нибудь может указать, что не так с моим кодом? Спасибо!

package Test;
import java.util.function.BiPredicate;

class Evaluation {
    public boolean evaluate(int a, int b) {
        if (a-b ==5){
            return true ;
        }
        return false; 
    }

    public void methodTest() {
        BiPredicate<Integer, Integer> biPredicate = Evaluation::evaluate;
        System.out.println(biPredicate.test(6,1));
    }
}

Изменить: После прочтения ответов мне было интересно, если это так, что ссылка на метод экземпляра по имени класса работает только в некоторых функциональных интерфейсах, но не в других? Например,

BiPredicate <String, Integer> biPredicate =  String::startsWith;

не компилируется, пока:

Predicate <String> predicate = String::isEmpty;

компилирует. Если это так, есть ли страница / учебное пособие / что-нибудь, на что кто-нибудь может отослать меня, чтобы объяснить, какие интерфейсы функций совместимы, а какие нет?

3 ответа

Если ваш метод является методом экземпляра, то вы должны вызвать его в некотором экземпляре, например:

public void methodTest(){
    BiPredicate<Integer, Integer> biPredicate = this::evaluate;
    System.out.println(biPredicate.test(6,1));
}

Поскольку вы не используете какие-либо переменные экземпляра или метод, вы можете просто сделать его статическим и сохранить его как есть.

При статической ссылке на метод экземпляра возвращаемый функтор принимает дополнительный аргумент, представляющий экземпляр.

interface Func {
    boolean evaluate(Evaluation instance, int a, int b);
}
...
Func biPredicate = Evaluation::evaluate;
System.out.println(biPredicate.evaluate(new Evaluation(), 6, 1));

Но вам нужно будет передать экземпляр Evaluation при звонке

Так как ваш evaluate Метод не использует поля экземпляра, вы можете сделать это staticто вам не нужно передавать экземпляр, и вы можете использовать только BiPredicate<Integer, Integer> как ты пытался.

Я все еще пытаюсь выяснить правило, которое применяется, но проблема исчезнет, ​​если вы используете

BiPredicate<Integer, Integer> biPredicate = this::evaluate;

Я ломаю голову над https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html но насколько я могу понять, потому что Evaluation::evaluate заставляет компилятор создать произвольный объект типа Evaluationи вы вызываете это из объекта такого типа, что правило другое. Вы должны вызывать его из определенного объекта, внутри которого methodTest метод появляется.

Хотя у меня нет объяснения, решение состоит в том, чтобы использовать this::evaluate, Это однозначно связывает ссылку на метод с вызывающим его объектом.

Примечание: вам не нужно оценивать boolean в качестве условного для того, чтобы вывести boolean от boolean, Вы могли бы просто return a - b == 5;,

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

Я думаю, что ОП пытается достичь упущения.

Я понимаю, что OP пытается понять, почему что-то вроде этого сработает:

    String str = "abc";
    Predicate<String> methodRef = str::startsWith; 
    methodRef.test("s");

а потом,

Predicate <String> predicate = String::isEmpty 

Работает и аналогично, почему бы не

Predicate <String> predicate =  String::startsWith;

Компиляция, которая принимает компиляцию имени класса String.

Это просто потому, что Predicate в основном принимает любой аргумент и возвращает логическое значение. Это неправильная установка для данной проблемы.

Вместо этого вы можете попробовать,

BiFunction<String, String, Boolean> methodRef2 = String::startsWith;
methodRef2.apply("sdsdfsd", "sdfsdf");

Это будет работать, поскольку для startwith требуется исходная строка, строка для проверки и возвращаемое значение. В основном есть 4 способа вызывать ссылки на методы в Java 8

  1. Вызов статических методов.
  2. Вызов методов экземпляра.
  3. Вызов методов класса
  4. Конструкторы
Другие вопросы по тегам