MethodHandle - 这是什么意思?
我正在研究 JDK 1.7 的新功能,但我不明白 MethodHandle 的设计目的是什么?我理解(直接)调用静态方法(以及在本例中使用简单的 Core Reflection API)。我还理解(直接)调用虚拟方法(非静态、非最终)(以及使用需要遍历类层次结构 obj.getClass().getSuperclass()
的 Core Reflection API) 。非虚方法的调用可以视为前一种方法的特例。
是的,我知道存在超载问题。如果您想调用方法,您必须提供准确的签名。您无法以简单的方式检查重载方法。
但是,MethodHandle 是什么?反射 API 允许您“查看”对象内部,无需任何预先假设(例如实现接口)。您可以出于某种目的检查该对象。但MethodHandle又是怎样设计的呢?为什么以及何时应该使用它?
更新:我现在正在阅读此http ://blog.headius.com/2008/09/first-taste-of-invokedynamic.html文章。根据它的说法,主要目标是简化在 JVM 上运行的脚本语言的生活,而不是 Java 语言本身。
UPDATE-2:我读完上面的链接,其中引用了一些内容:
JVM 将成为构建动态语言的最佳 VM,因为它已经是一个动态语言 VM。 InvokeDynamic 将通过向一流 JVM 公民推广动态语言来证明这一点。
使用反射来调用方法效果很好......除了一些问题。方法对象必须从特定类型中检索,不能以通用方式创建。<...>
...反射调用比直接调用慢很多。多年来,JVM 已经非常擅长快速进行反射调用。现代 JVM 实际上在幕后生成一堆代码,以避免旧 JVM 处理的大量开销。但简单的事实是,通过任意数量的层进行反射访问总是比直接调用慢,部分原因是完全泛化的“调用”方法必须检查并重新检查接收者类型、参数类型、可见性和其他细节,但是还因为参数必须全部是对象(因此基元被对象装箱)并且必须作为数组提供以涵盖所有可能的参数(因此参数被数组装箱)。
对于执行一些反射调用的库来说,性能差异可能并不重要,特别是如果这些调用主要是为了在内存中动态设置一个静态结构来进行正常调用。但在动态语言中,每个调用都必须使用这些机制,这会严重影响性能。
http://blog.headius.com/2008/09/first -taste-of-invokedynamic.html
所以,对于Java程序员来说它本质上是没有用的。我说得对吗?从这个角度来看,它只能被认为是 Core Reflection API 的替代方式。
UPDATE-2020: 事实上,MethodHandle 可以被认为是 Core Reflection API 的更强大的替代品。从 JDK 8 开始,还有使用它的 Java 语言功能。
I am studying new features of JDK 1.7 and I just can't get it what MethodHandle is designed for? I understand (direct) invocation of the static method (and use of Core Reflection API that is straightforward in this case). I understand also (direct) invocation of the virtual method (non-static, non-final) (and use of Core Reflection API that requires going through Class's hierarchy obj.getClass().getSuperclass()
). Invocation of non-virtual method can be treated as special case of the former one.
Yes, I aware that there is an issue with overloading. If you want to invoke method you have to supply the exact signature. You can't check for overloaded method in easy way.
But, what is MethodHandle about? Reflection API allows you to "look on" the object internals without any pre-assumption (like implemented the interface). You can inspect the object for some purpose. But what is MethodHandle is designed too? Why and when should I use it?
UPDATE: I am reading now this http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html article. According to it, the main goal is to simplify life for scripting languages that runs atop of JVM, and not for Java Language itself.
UPDATE-2: I finish to read the link above, some quotation from there:
The JVM is going to be the best VM for building dynamic languages, because it already is a dynamic language VM. And InvokeDynamic, by promoting dynamic languages to first-class JVM citizens, will prove it.
Using reflection to invoke methods works great...except for a few problems. Method objects must be retrieved from a specific type, and can't be created in a general way.<...>
...reflected invocation is a lot slower than direct invocation. Over the years, the JVM has gotten really good at making reflected invocation fast. Modern JVMs actually generate a bunch of code behind the scenes to avoid a much of the overhead old JVMs dealt with. But the simple truth is that reflected access through any number of layers will always be slower than a direct call, partially because the completely generified "invoke" method must check and re-check receiver type, argument types, visibility, and other details, but also because arguments must all be objects (so primitives get object-boxed) and must be provided as an array to cover all possible arities (so arguments get array-boxed).
The performance difference may not matter for a library doing a few reflected calls, especially if those calls are mostly to dynamically set up a static structure in memory against which it can make normal calls. But in a dynamic language, where every call must use these mechanisms, it's a severe performance hit.
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
So, for Java programmer it is essentially useless. Am I right? From this point of view, It can be only considered as alternative way for Core Reflection API.
UPDATE-2020: Indeed, MethodHandle can be thought as s more powerful alternative to Core Reflection API. Starting with JDK 8 there are also Java Language features that use it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用 MethodHandles 可以做的是柯里化方法,更改参数的类型并更改它们的顺序。
方法句柄可以处理方法和字段。
MethodHandles 所做的另一个技巧是直接使用原语(而不是通过包装器)
MethodHandles 比使用反射更快,因为 JVM 中有更直接的支持,例如它们可以内联。它使用新的invokedynamic指令。
What you can do with MethodHandles is curry methods, change the types of parameters and change their order.
Method Handles can handle both methods and fields.
Another trick which MethodHandles do is use primitive direct (rather than via wrappers)
MethodHandles can be faster than using reflection as there is more direct support in the JVM e.g they can be inlined. It uses the new invokedynamic instruction.
将 MethodHandle 视为一种现代、更灵活、类型更安全的反射方式。
它目前处于生命周期的早期阶段 - 但随着时间的推移,有可能进行优化,变得比反射更快 - 以至于它可以变得与常规方法调用一样快。
Think of MethodHandle as a modern, more flexible, more typesafe way of doing reflection.
It's currently in the early stages of its lifecycle - but over time has the potential to be optimized to become must faster than reflection - to the point that it can become as fast as a regular method call.
java.lang.reflect.Method
在内存方面相对较慢且昂贵。方法句柄应该是一种将指针传递给 JVM 有机会优化的函数的“轻量级”方式。从 JDK8 开始,方法句柄没有得到很好的优化,并且 lambda 可能最初以类的形式实现(就像内部类一样)。java.lang.reflect.Method
is relatively slow and expensive in terms of memory. Method handles are supposed to be a "lightweight" way of passing around pointers to functions that the JVM has a chance of optimising. As of JDK8 method handles aren't that well optimised, and lambdas are likely to be initially implemented in terms of classes (as inner classes are).自从我问这个问题以来,已经快九年过去了。
JDK 14 是最后一个稳定版本,大量使用了 MethodHandle...
我创建了关于
invokedynamic
https://alex-ber.medium.com/explaining-invokedynamic-introduction-part-i-1079de618512。下面,我引用其中的相关部分。MethodHandle 可以被认为是 Core Reflection API 的更强大替代方案。 MethodHandle 就是这样一个对象,它存储有关方法(构造函数、字段或类似的低级操作)的元数据,例如方法的方法签名的名称等。采用它的一种方法是指向方法(取消引用的方法(构造函数、字段或类似的低级操作))。
Java 代码可以创建直接访问该代码可访问的任何方法、构造函数或字段的方法句柄。这是通过名为 MethodHandles.Lookup 的反射式、基于功能的 API 完成的。例如,可以从 Lookup.findStatic 获取静态方法句柄。还有来自 Core Reflection API 对象的转换方法,例如 Lookup.unreflect。
了解 Core Reflection API 和 MethodHandle 的两个关键区别非常重要。
使用 MethodHandle 时,访问检查仅在构造时执行一次,使用 Core Reflection API 时,它会在每次调用调用方法时执行(并且每次都会调用安全管理器,从而降低性能)。
核心反射API调用方法是常规方法。在 MethodHandle 中,所有 invoke* 变体都是签名多态方法。
基本上,访问检查意味着您是否可以访问方法(构造函数、字段或类似的低级操作)。例如,如果方法(构造函数、字段或类似的低级操作)是私有的,则通常无法调用它(从字段获取值)。
与Reflection API相反,JVM可以完全透视MethodHandles并尝试优化它们,因此性能更好。
注意:使用MethodHandle,您还可以生成实现逻辑。请参阅动态 hashCode 实现。第五部分 https:// alex-ber.medium.com/explaining-invokedynamic-dynamical-hashcode-implementation-part-v-16eb318fcd47了解详情。
Almost 9 years past since I've asked this question.
JDK 14 is last stable version that has massive usage of MethodHandle...
I've create mini-series of articles about
invokedynamic
https://alex-ber.medium.com/explaining-invokedynamic-introduction-part-i-1079de618512. Below, I'm quoting the relevant parts from there.MethodHandle can be thought as a more powerful alternative to Core Reflection API. MethodHandle is such an Object which stores the metadata about the method (constructor, field, or similar low-level operation), such as the name of the method signature of the method etc. One way took on it is a destination of the pointer to method (de-referenced method (constructor, field, or similar low-level operation)).
Java code can create a method handle that directly accesses any method, constructor, or field that is accessible to that code. This is done via a reflective, capability-based API called MethodHandles.Lookup. For example, a static method handle can be obtained from Lookup.findStatic. There are also conversion methods from Core Reflection API objects, such as Lookup.unreflect.
It is important to understand 2 key difference from Core Reflection API and MethodHandle.
With MethodHandle access check is done only once in construction time, with Core Reflection API it is done on every call to invoke method (and Security Manager is invoked each time, slowing down the performance).
Core Reflection API invoke method is regular method. In MethodHandle all invoke* variances are signature polymorphic methods.
Basically, access check means whether you can access method (constructor, field, or similar low-level operation). For example, if the method (constructor, field, or similar low-level operation) is private, you can’t normally invoke it (get value from the field).
As opposed to the Reflection API, the JVM can completely see-through MethodHandles and will try to optimize them, hence the better performance.
Note: With MethodHandle you can also generate implementation logic. See
Dynamical hashCode implementation. Part V
https://alex-ber.medium.com/explaining-invokedynamic-dynamical-hashcode-implementation-part-v-16eb318fcd47 for details.