是否可以将方法引用转换为MethodHandle?

是否可以将方法引用(例如SomeClass::someMethod )转换为MethodHandle实例? 我想要编译时检查的好处(确保存在类和方法)以及使用MethodHandle API内省方法的能力。

用例:当且仅当请求未被特定方法触发时(我要避免无限递归),我才需要执行代码。 我想进行编译时检查以确保类/方法存在但运行时检查以将调用者与方法进行比较。

那么回顾一下: 是否可以将方法引用转换为MethodHandle

好吧,如果您能够承担额外的开销和安全隐患,您可以使用Serializablefunctioninterface并解码方法引用实例的序列化forms,以找到此答案中演示的目标,或者再次提出此问题及其答案 。

但是,您应该重新考虑您的软件设计。 “避免无限递归”不应该通过解码某种参数对象来修复,尤其是如果你的假设是,这个实际的参数值代表你的方法的调用者 。 你怎么会强迫这种奇怪的关系?

即使是简单的代码更改,例如引用委托给其他方法的方法也会破坏您的检查。 这是一个简单的示例,显示了您的方法的细微问题:

 public class SimpleTest { public static void main(String... arg) { run(SimpleTest::process); } static void run(BiConsumer 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首先会引发无休止的递归; 似乎有根本错误的东西……