是否可以将方法引用(例如SomeClass::someMethod
)转换为MethodHandle
实例?我想要编译时检查的好处(确保类和方法存在)以及使用MethodHandle
API 内省方法的能力。
用例:当且仅当请求不是由特定方法触发时(以避免无休止的递归),我有需要执行的代码。我想要一个编译时检查来确保类/方法存在,但是运行时检查来比较调用者和方法。
回顾一下:是否可以将方法引用转换为 aMethodHandle
?
是否可以将方法引用(例如SomeClass::someMethod
)转换为MethodHandle
实例?我想要编译时检查的好处(确保类和方法存在)以及使用MethodHandle
API 内省方法的能力。
用例:当且仅当请求不是由特定方法触发时(以避免无休止的递归),我有需要执行的代码。我想要一个编译时检查来确保类/方法存在,但是运行时检查来比较调用者和方法。
回顾一下:是否可以将方法引用转换为 aMethodHandle
?
好吧,如果您能承受额外的开销和安全隐患,您可以使用Serializable
函数interface
并解码方法引用实例的序列化形式,以找到此答案中演示的目标,或再次提出此问题及其答案。
但是,您真的应该重新考虑您的软件设计。“避免无休止的递归”不应该通过解码某种参数对象来解决,特别是如果你的假设是,这个实际的参数值代表你的方法的调用者。你将如何执行这种奇怪的关系?
即使是简单的代码更改(例如引用委托给另一个方法的方法)也会破坏您的检查。这是一个简单的示例,显示了您的方法的细微问题:
public class SimpleTest {
public static void main(String... arg) {
run(SimpleTest::process);
}
static void run(BiConsumer<Object,Object> c) {
c.accept("foo", "bar");
}
static void process(Object... arg) {
Thread.dumpStack();
}
}
运行此程序时,它将打印如下内容:
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1329)
at SimpleTest.process(SimpleTest.java:16)
at SimpleTest.lambda$MR$main$process$a9318f35$1(SimpleTest.java:10)
at SimpleTest$$Lambda$1/26852690.accept(Unknown Source)
at SimpleTest.run(SimpleTest.java:13)
at SimpleTest.main(SimpleTest.java:10)
表明生成的实例中的方法引用不是预期的SimpleTest::process
,而是SimpleTest::lambda$MR$main$process$a9318f35$1
最终会调用process
的。原因是某些操作(此处为varargs处理)不是由生成的interface
实例执行的,而是由合成方法执行的,就像您编写run((a,b)-> SimpleTest.process(a,b))
的 . 唯一的区别是合成方法的名称。
你不应该设计依赖于如此脆弱的内省的软件。如果你想避免递归,一个简单的ThreadLocal
标志告诉你是否已经在你的特定方法中就可以了。但可能值得问问自己,为什么你的 API 一开始就会引发无休止的递归;似乎有什么根本上的错误……</p>