我正在尝试使用方法引用来捕获方法调用,并且遇到了一些限制。这很好用:
<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
我不清楚限制是什么。理想情况下,我想使用方法引用来捕获标准setter上的调用。有没有办法做到这一点?
答案 0 :(得分:13)
这里有两个问题:
Function
,它必须返回一些东西。 setBar
不会返回任何内容。Function
只需输入一个,但您有两个输入:Foo
您要调用setBar
,String
1}}你要传递给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);
答案 1 :(得分:8)
Foo::getBar
对应于一个带Foo
(目标对象)并返回String
的函数。接口Function<Foo, String>
可用于表示此类函数。
另一方面,Foo::setBar
对应于一个带有两个参数的函数,Foo
(目标对象)和String
(第一个参数)。匹配的界面是BiConsumer<Foo, String>
。这意味着您需要BiConsumer
的重载:
<T, U> void capture(BiConsumer<T, U> setter) {
// ...
}
答案 2 :(得分:3)
暴露语法糖方法参考,您应该看到,
Foo::getBar
等于
(Foo)foo -> foo.getBar()
是Function <Foo, String>
但是
Foo::setBar
在这个上下文中是两个变量(foo
和一些String str
)的函数,因此它不是一个变量的函数(Function
)
您应该看到更方便的答案,允许method references的位置:
引用特定类型的任意对象的实例方法(本例)
在上面的说明中有一个例子,几乎与你的情况相同。据说,等效的lambda表达式将采用两个参数(在本例中为Foo
和String
),这不是Function
对构造函数的引用(完全不是这种情况)