MethodHandle - 这是什么一回事?

时间:2012-01-11 17:27:09

标签: java jvm java-7 invokedynamic methodhandle

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

是的,我知道重载存在问题。如果要调用方法,则必须提供确切的签名。您无法以简单的方式检查重载方法。

但是,MethodHandle是关于什么的? Reflection 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。但简单的事实是,通过任意数量的层反射访问总是比直接调用慢,部分原因是完全通用的“调用”方法必须检查并重新检查接收器类型,参数类型,可见性和其他细节,但因为参数必须都是对象(所以原语是对象框),并且必须作为一个数组提供,以涵盖所有可能的arities(所以参数得到数组框)。

     

对于执行一些反射调用的库,性能差异可能无关紧要,特别是如果这些调用主要是为了在内存中动态设置静态结构,可以进行正常调用。但是在动态语言中,每个调用都必须使用这些机制,这是一个严重的性能损失。

http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html

因此,对于Java程序员来说,它基本上是无用的。我对吗?从这个角度来看,它只能被视为Core Reflection API的替代方式。

4 个答案:

答案 0 :(得分:33)

使用MethodHandles可以做的是咖喱方法,更改参数类型并更改其顺序。

方法句柄可以处理方法和字段。

MethodHandles所做的另一个技巧是使用原始直接(而不是通过包装器)

MethodHandles可以比使用反射更快,因为JVM中有更多的直接支持,例如它们可以内联。它使用新的invokedynamic指令。

答案 1 :(得分:11)

java.lang.reflect.Method在内存方面相对较慢且昂贵。方法句柄应该是一种“轻量级”方式,可以将指针传递给JVM有机会优化的函数。从JDK8开始,方法句柄的优化程度不高,lambdas最初可能是以类的形式实现的(如内部类)。

答案 2 :(得分:9)

将MethodHandle视为一种现代的,更灵活,更安全的反射方式。

它目前处于生命周期的早期阶段 - 但随着时间的推移,有可能被优化成必须比反射更快 - 以至于它可以变得像常规方法调用一样快。

答案 3 :(得分:2)

问了这个问题已经过去9年了。 JDK 14是最后一个稳定版本,它大量使用了MethodHandle ... 我创建了关于invokedynamic https://alex-ber.medium.com/explaining-invokedynamic-introduction-part-i-1079de618512的微型文章系列。在下面,我引用了其中的相关部分。

MethodHandle可以看作是Core Reflection API的功能强大的替代方案。 MethodHandle是一种对象,用于存储有关方法的元数据(构造函数,字段或类似的低级操作),例如方法的方法签名的名称等。采用的一种方法是指向该方法的指针的目标。方法(取消引用的方法(构造函数,字段或类似的低级操作))。

Java代码可以创建直接访问该代码可访问的任何方法,构造函数或字段的方法句柄。这是通过一个基于反射的,基于功能的API(称为MethodHandles.Lookup)完成的。例如,可以从Lookup.findStatic获取静态方法句柄。还有来自Core Reflection API对象的转换方法,例如Lookup.unreflect。

了解与Core Reflection API和MethodHandle的两个主要区别很重要。

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

  • Core Reflection API调用方法是常规方法。在MethodHandle中,所有invoke *方差都是签名多态方法。

基本上,访问检查意味着您可以访问方法(构造函数,字段或类似的低级操作)。例如,如果方法(构造函数,字段或类似的低级操作)是私有的,则通常无法调用它(从字段中获取值)。

与Reflection API相对,JVM可以完全透视MethodHandles并将尝试对其进行优化,从而获得更好的性能。

注意:使用 MethodHandle ,您还可以生成实现逻辑。有关详细信息,请参见Dynamical hashCode implementation. Part V https://alex-ber.medium.com/explaining-invokedynamic-dynamical-hashcode-implementation-part-v-16eb318fcd47