MethodHandle - What is it all about?
Asked Answered
G

4

59

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.

Glucose answered 11/1, 2012 at 17:27 Comment(5)
No, absolutely not. That post is over 3 years old. A great many frameworks developers are looking closely at MH and invokedynamic and ways to use them to help developers.Jeff
Can you provide an example of such a use? What is possible to do with MethodHandle that is impossible to do with Core Reflection API?Glucose
For example, interacting with a security manager. setAccessible() will kill you under a security manager, whereas the Lookup mechanism is completely safe. Lookup also lets you create an MH within a context where you can see it, and then pass the reference out to unprivileged contexts.Jeff
Practically, I've never experience problems with setAccessible(). In theory I can use AccessController.doPrivileged(new PrivilegedAction() idiom.Glucose
Maybe it is helpful to take a look at en.cppreference.com/w/cpp/utility/functional/functionPhocomelia
G
7

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

Glucose answered 8/9, 2020 at 15:56 Comment(1)
"In MethodHandle all invoke* variances are signature polymorphic methods.` - MethodHandle.invokeWithArguments (both overloads) are normal methods.Clint
S
34

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.

Spoon answered 11/1, 2012 at 17:37 Comment(6)
in addition, the stacktraces when doing invocation are much nicer than with reflection. as a downside, you cannot call a methodhandle via reflection (but the other way round)Pollie
MethodHandles do not use the invokedynamic instruction. But there’s a relationship the other way: the invokedynamic instruction heavily relies on MethodHandles.Barneybarnhart
@Peter What exactly you mean by "Another trick which MethodHandles do is use primitive direct (rather than via wrappers)"?Stannite
@Stannite If you use a Method, it will wrap arguments and return value. i.e. calling it on a double method(double d) { return d; } creates at least two objects. With MethodHandles it is smart enough to remove the need to wrap the argument or return value on invoke even though notionally it takes an Object... and returns an ObjectSpoon
This is because it doesn't use invokedynamic, but invokepolymorphic which was created just for this. If you look at the bytecode you'll see that invokedynamic doesn't only store the original, ignored signature but also the signature you called it with.Labored
Actually, it looks in the bytecode like there is a method double MethodHandle.invokeExact(double) there.Clint
J
12

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.

Jeff answered 11/1, 2012 at 19:44 Comment(1)
It is against basic java philosophy to give only one way possible for doing things for Java programmer. I know introducing some features in JDK 1.5 changed these, but features in JDK 1.5 was useful for Java Programmer (well, I know, some of them are disputed), MethodHandle feature is not useful as far I see now for regular Java Developer.Glucose
G
11

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

Giroux answered 11/1, 2012 at 17:34 Comment(1)
@tackline, I know that java.lang.reflect.Method is relatively slow. I also saw some statistic that show that MehodHandle is not that fast. So, the main reason is performance? What is lambda is doing in java? Lambda-calculus is totally different approach to programming...Glucose
G
7

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

Glucose answered 8/9, 2020 at 15:56 Comment(1)
"In MethodHandle all invoke* variances are signature polymorphic methods.` - MethodHandle.invokeWithArguments (both overloads) are normal methods.Clint

© 2022 - 2024 — McMap. All rights reserved.