7

我正在尝试使用方法引用来捕获方法调用并且遇到了一些限制。这工作正常:

<T> void capture(Function<T, ?> in) {
}

private interface Foo {
  String getBar();
} 

capture(Foo::getBar);

但是,如果我将 Foo.setBar 的签名更改为如下所示:

private interface Foo {
  void setBar(String bar);
}

capture(Foo::setBar);

我收到一个错误:

Cannot make a static reference to the non-static method setBar(String) from the type MyTest.Foo

我不清楚限制是什么。理想情况下,我想使用方法引用来捕获标准设置器上的调用。有没有办法做到这一点?

4

3 回答 3

13

这里有两个问题:

  • 您正在使用Function,它必须返回一些东西。setBar不返回任何东西。
  • Function只接受一个输入,但你有两个输入:Foo你要调用setBar的,以及String你要传入的参数setBar

如果你改为使用BiConsumer(它有一个void返回类型和两个输入)它工作正常:

static <T, U> void capture(BiConsumer<T, U> in) {
}

您可以重载您的capture方法以具有两个签名:

static <T, U> void capture(BiConsumer<T, U> in) { }
static <T> void capture(Function<T, ?> in) { }

然后使用两个方法引用:

capture(Foo::setBar);
capture(Foo::getBar);
于 2014-05-21T21:38:59.257 回答
8

Foo::getBar对应于接受 a Foo(目标对象)并返回 a的函数String。接口Function<Foo, String>可以用来表示这样的功能。

另一方面,Foo::setBar对应于一个接受两个参数的函数,a Foo(目标对象)和a String(第一个参数)。匹配界面为BiConsumer<Foo, String>. 这意味着您需要重载BiConsumer

<T, U> void capture(BiConsumer<T, U> setter) {
    // ...
}
于 2014-05-21T21:39:19.073 回答
3

公开语法糖方法参考,你应该看到,

Foo::getBar

等于

(Foo)foo -> foo.getBar()

这是Function <Foo, String>

Foo::setBar

在这种情况下是两个变量(foo和一些String str)的函数,所以它不是一个变量的函数(Function

对于您应该看到的更方便的答案,允许方法引用的位置:

  1. 引用静态方法(根本不是这种情况)
  2. 引用特定对象的实例方法(根本不是这种情况)
  3. 引用特定类型的任意对象的实例方法(本例)

    在上面的说明中有一个示例,与您的情况几乎相同。据说,等效的 lambda 表达式将采用两个参数(在本例中为FooString),这不是Function

  4. 对构造函数的引用(根本不是这种情况)

于 2014-05-21T21:37:28.547 回答