MethodHandle - 这是什么?

2022-01-16 00:00:00 jvm java java-7 invokedynamic methodhandle

我正在研究 JDK 1.7 的新功能,但我无法理解 MethodHandle 的设计用途?我理解(直接)调用静态方法(以及在这种情况下直接使用核心反射 API).我也理解(直接)调用虚拟方法(非静态,非最终)(以及使用需要通过类的层次结构obj.getClass().getSuperclass()的核心反射API).非虚方法的调用可以视为前者的特例.

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.

但是,MethodHandle 是关于什么的?反射 API 允许您观看"没有任何预先假设的对象内部结构(如实现接口).您可以出于某种目的检查对象.但是 MethodHandle 又是怎样设计的呢?为什么以及何时应该使用它?

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?

更新:我现在正在阅读这个 http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html 文章.据它说,主要目标是简化运行在 JVM 之上的脚本语言的生活,而不是简化 Java 语言本身.

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:我读完上面的链接,从那里引用一些:

UPDATE-2: I finish to read the link above, some quotation from there:

JVM 将成为构建动态语言的最佳 VM,因为它已经是动态语言 VM.而 InvokeDynamic 通过向一流的 JVM 公民推广动态语言,将证明这一点.

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.<...>

...反射调用比直接调用慢很多.多年来,JVM 在快速实现反射调用方面做得非常好.现代 JVM 实际上会在幕后生成一堆代码,以避免旧 JVM 处理的大量开销.但简单的事实是,通过任意数量的层的反射访问总是比直接调用慢,部分原因是完全通用的调用"方法必须检查并重新检查接收器类型、参数类型、可见性和其他细节,而且因为参数必须都是对象(因此原语被对象装箱)并且必须作为数组提供以涵盖所有可能的参数(所以参数得到数组装箱).

...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

所以,对于 Java 程序员来说,它本质上是无用的.我对吗?从这个角度来看,它只能被认为是Core Reflection API的替代方式.

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: 事实上,MethodHandle 可以被认为是核心反射 API 的更强大的替代方案.从 JDK 8 开始,还有一些 Java 语言功能使用它.

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.

推荐答案

我问这个问题已经快 9 年了.JDK 14 是最后一个稳定版本,大量使用 MethodHandle ...我创建了关于 invokedynamic https://alex-ber.medium.com/explaining-invokedynamic-introduction-part-i-1079de618512.下面,我引用了他们的相关部分.

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 their.

MethodHandle 可以被认为是 Core Reflection API 的一个更强大的替代方案.MethodHandle 是这样一个对象,它存储有关方法的元数据(构造函数、字段或类似的低级操作),例如方法的方法签名的名称等.采用它的一种方法是指向的指针的目的地方法(取消引用的方法(构造函数、字段或类似的低级操作)).

MethodHandle can be thought as s 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 代码可以创建直接访问该代码可访问的任何方法、构造函数或字段的方法句柄.这是通过名为 MethodHandles.Lookup 的基于功能的反射 API 完成的.例如,可以从 Lookup.findStatic 获得静态方法句柄.还有来自 Core Reflection API 对象的转换方法,例如 Lookup.unreflect.

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.

了解 Core Reflection API 和 MethodHandle 的 2 个关键区别很重要.

It is important to understand 2 key difference from Core Reflection API and MethodHandle.

  • 使用 MethodHandle 访问检查仅在构造时进行一次,使用 Core Reflection API 时,每次调用调用方法时都会进行检查(并且每次都会调用 Securty Manager,从而降低性能).

  • 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 Securty Manager is invoked each time, slowing down the performance).

Core Reflection API 调用方法是常规方法.在 MethodHandle 中,所有的 invoke* 变化都是签名多态方法.

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).

与反射 API 不同,JVM 可以完全透视 MethodHandles,并尝试对其进行优化,从而获得更好的性能.

As opposed to the Reflection API, the JVM can completely see-through MethodHandles and will try to optimize them, hence the better performance.

注意:使用MethodHandle您还可以生成实现逻辑.请参阅 动态 hashCode 实现.第五部分 https://alex-ber.medium.com/explaining-invokedynamic-dynamical-hashcode-implementation-part-v-16eb318fcd47 了解详情.

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.

相关文章