Categories
Java

Java: invokedynamic

The use of “invokedynamic” instruction is another advanced feature in Java that is less well-known. This JVM instruction allows for dynamic method invocation at runtime, instead of the traditional static linking that happens at compile-time.

The main advantage of using invokedynamic is that it allows for more flexibility and performance when working with dynamically typed languages, such as JavaScript or Ruby, that run on the JVM using a language runtime.

Invokedynamic also allows for more advanced features such as:

  • Method handle: A MethodHandle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.
  • Dynamic linking: The Java Language Specification allows for dynamic linking, which means that you can change the behavior of a method at runtime.
  • Improved performance: Invokedynamic can improve the performance of your code by avoiding the overhead of reflection and dynamic method dispatch.

Invokedynamic is an advanced feature that requires knowledge of the JVM internals, and it’s not commonly used by Java developers, but for developers who work on dynamic languages or write performance-critical code, it can be a powerful tool to have in your toolbox.

Lets start with stupid Hello World example:

import java.lang.invoke.*;

public class InvokeDynamicExample {
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType type = MethodType.methodType(String.class, String.class);
        CallSite site = LambdaMetafactory.metafactory(
                lookup, "concat", MethodType.methodType(String.class, String.class),
                type.erase(), lookup.findVirtual(String.class, "concat", type), type);
        MethodHandle mh = site.getTarget();
        String result = (String) mh.invokeExact("Hello, ", "world!");
        System.out.println(result); // prints "Hello, world!"
    }
}

This example uses the LambdaMetafactory class to create a dynamic invocation of the concat method on the String class, using a MethodHandle to invoke the method at runtime.

This example uses the MethodHandles and MethodType classes to define the signature of the concat method, and the CallSite class to represent the target of the invocation.

This allows for a more flexible way of invoking methods, that doesn’t require knowing the target method at compile-time and allows for more dynamic behavior.

One more useful example:

import java.lang.invoke.*;

public class InvokeDynamicExample {
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType type = MethodType.methodType(int.class, int.class);
        CallSite site = LambdaMetafactory.metafactory(
                lookup, "compare", MethodType.methodType(int.class, Object.class, Object.class),
                type.erase(), lookup.findVirtual(Comparable.class, "compareTo", type), type);
        MethodHandle mh = site.getTarget().asType(type);
        int result = (int) mh.invokeExact(5, 3);
        System.out.println(result); // prints 2
    }
}

This example uses the LambdaMetafactory class to create a dynamic invocation of the compareTo method on the Comparable interface, using a MethodHandle to invoke the method at runtime.

This allows for comparing objects of any type that implements the Comparable interface, without knowing the specific type at compile time.

This example can be useful in cases where you have a collection of objects that implement the Comparable interface and you want to sort them without knowing the specific type of the objects, you can use this example to sort them in a generic way!

Leave a Reply

Your email address will not be published. Required fields are marked *