What is a MethodHandle?
Starting with Java 7, another set of API MethodHandle is provided. Its function is similar to reflection, which can access type information at run time, but it is said that its execution efficiency is higher than reflection, which is also called modern reflection of Java.
The official definition is as follows:
A method handle 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.
How to reflect by?
To access the methods and properties in a class through the method handle, generally speaking, only four steps are required:
- Create Lookup
- Create MethodType
- Get MethodHandle based on Lookup and MethodType
- Call MethodHandle
Create a reflective target class for later examples
public class Hello { private String name; public void hello(String name){ System.out.println("hello "+name); } public void say(String name){ System.out.println("say "+name); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
-
Create Lookup
Use the following code to create a lookup. The lookup obtained in this way is very powerful. It supports all bytecode operations supported by the calling class.
MethodHandles.Lookup lookup = MethodHandles.lookup();
It can also be created using the publicLookup method, but a lookup created in this way can only access public members in the class.
MethodHandles.Lookup publicLookup=MethodHandles.publicLookup();
-
Create MethodType
The first parameter is the return type of the method. The second parameter starts with the formal parameter type of the method (in the example, there is only one String parameter, but there can be multiple)
MethodType.methodType(Void.class, String.class)
-
Create MethodHandle based on Lookup and MethodType
MethodHandle helloMethod = lookup.findVirtual(Hello.class, "hello", MethodType.methodType(Void.class, String.class));
-
Call the object method hello by passing in the object instance targetInstance and the method parameter string "MethodHandle" through the MethodHandle
Hello targetInstance = new Hello(); helloMethodHandle.invoke(helloInstance,"MethodHandle");
-
Get the property value by passing in the object instance helloInstance and property name through MethodHandle
//To access the attribute, you need to get the Field through reflection. If the changed attribute is private, you also need to set setAccessible of the Field to true Field nameField = Hello.class.getDeclaredField("name"); nameField.setAccessible(true); MethodHandle nameHandle = lookup.unreflectGetter(nameField); System.out.println((String) nameHandle.invoke(targetInstance));
Reflection API
Create MethodHandle
The MethodHandle is created mainly through the following methods in the lookup
Create constructor MethodHandle
public MethodHandle findConstructor(Class<?> refc, MethodType type)
refc: class to retrieve
type: the MethodType of the corresponding constructor
Create instance method MethodHandle
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type)
Name: method name
Create MethodHandle of class method
public MethodHandle findStatic(Class<?> refc, String name, MethodType type)
Create an access MethodHandle for a non private field. Note that this is not the javabean Setter method to get the field, and it has nothing to do with it. We can access this property through the setter method handle.
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type)
Correspondingly, if you want to set the value of this property, use the Setter method handle
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type)
Call the target method through MethodHandle
public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
epilogue
It can be seen from the above that the MethodHandle needs to use the reflection API when accessing the attribute value of the target object. Recall the conclusion in the article java reflection, "but if you use this method in Java 9 or later, you will see such a warning. Java 16 starts to deny illegal access by default, so it will directly report an error" . Therefore, neither of the two methods of reflection and invoke packages are complete reflection. Java also provides a method of complete reflection, that is, through UnSafe, which is explained in detail below.