使用Java上的运行时确定的实例上的方法引用

时间:2017-01-17 20:52:38

标签: java java-8 method-reference

我正在测试使用方法引用的规则,但我编写的代码无法编译。编译器不断告诉我,我无法从静态上下文中引用非静态方法。但是,在Java Documents中,它明确写道可以使用" ::" to"引用特定类型的任意对象的实例方法"。任何人都可以指出我的代码有什么问题吗?谢谢!

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;

编译。 如果是这种情况,是否有任何人可以引用我的页面/教程/解释哪些功能接口兼容哪些不兼容?

4 个答案:

答案 0 :(得分:2)

如果您的方法是实例方法,则必须在某个实例上调用它,例如:

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

由于您没有使用任何实例变量或方法,您可以简单地将其设置为静态并保持原样。

答案 1 :(得分:2)

静态引用实例方法时,返回的仿函数会使用另一个表示实例的参数。

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,然后您不需要传递实例,可以 em>只使用你试过的BiPredicate<Integer, Integer>

答案 2 :(得分:0)

我仍在尝试找出适用的规则,但如果使用

,问题就会消失
BiPredicate<Integer, Integer> biPredicate = this::evaluate;

我在https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13感到困惑但是尽可能接近,因为Evaluation::evaluate强制编译器创建Evaluation类型的任意对象,并且你正在调用它来自该类型的对象,规则是不同的。您需要从显示methodTest方法的特定对象中调用它。

虽然我没有解释,但解决方法是使用this::evaluate。这明确地将方法引用与调用它的对象联系起来。

附注:您无需将boolean评估为条件,以便从boolean派生boolean。你可以return a - b == 5;

答案 3 :(得分:0)

我回答这个问题可能为时已晚,但是由于问题仍未得到解答,我想尝试一个答案。

我认为OP想要实现的目标很遗憾。

我了解OP正在尝试了解为什么这样的方法会起作用:

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

然后

Predicate <String> predicate = String::isEmpty 

以类似的方式工作,为什么不

Predicate <String> predicate =  String::startsWith;

使用String类名进行编译的Compile。

这仅仅是因为,Predicate基本上接受任何参数并返回一个布尔值。这不是针对此问题的正确设置。

您可以改为尝试

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

这将起作用,因为startswith需要源字符串,用于检查和返回值的字符串。基本上,有4种方法可以在Java 8中调用方法引用。

  1. 静态方法调用。
  2. 实例方法调用。
  3. 类方法调用
  4. 构造函数