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

Gil*_*ili 10 java java-8 methodhandle method-reference

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

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

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

Hol*_*ger 4

好吧,如果您能承受额外的开销和安全隐患,您可以使用函数Serializableinterface解码方法引用实例的序列化形式来查找目标,如本答案中所示或再次提出此问题及其答案

\n\n

但是,您确实应该重新考虑您的软件设计。\xe2\x80\x9c避免无休止的递归\xe2\x80\x9d 不应该通过解码某种参数对象来修复\xe2\x80\x99,特别是如果你的假设是,这个实际参数值代表你的方法的调用者。你将如何加强这种奇怪的关系?

\n\n

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

\n\n
public class SimpleTest {\n    public static void main(String... arg) {\n        run(SimpleTest::process);\n    }\n    static void run(BiConsumer<Object,Object> c) {\n        c.accept("foo", "bar");\n    }\n    static void process(Object... arg) {\n        Thread.dumpStack();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

运行该程序时,它会打印如下内容:

\n\n
java.lang.Exception: Stack trace\n    at java.lang.Thread.dumpStack(Thread.java:1329)\n    at SimpleTest.process(SimpleTest.java:16)\n    at SimpleTest.lambda$MR$main$process$a9318f35$1(SimpleTest.java:10)\n    at SimpleTest$$Lambda$1/26852690.accept(Unknown Source)\n    at SimpleTest.run(SimpleTest.java:13)\n    at SimpleTest.main(SimpleTest.java:10)\n
Run Code Online (Sandbox Code Playgroud)\n\n

显示生成的实例中的方法引用不是预期SimpleTest::process,而是SimpleTest::lambda$MR$main$process$a9318f35$1最终将调用process. 原因是某些操作(此处为可变参数处理)不是由生成的interface实例执行,而是由合成方法执行,就像您编写的那样run((a,b)-> SimpleTest.process(a,b))。唯一的区别是合成方法的名称。

\n\n

你不应该依赖如此脆弱的内省来设计软件。如果你想避免递归,一个简单的ThreadLocal标志告诉你是否已经在你的特定方法中就可以完成这项工作。但也许值得问问自己,为什么你的 API 首先会引发无休止的递归?似乎有一些根本性错误\xe2\x80\xa6

\n