[Java basics] advanced reflection

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:

  1. Create Lookup
  2. Create MethodType
  3. Get MethodHandle based on Lookup and MethodType
  4. 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;
    }

}
  1. 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();
    
  2. 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)
    
  3. Create MethodHandle based on Lookup and MethodType

    MethodHandle helloMethod = lookup.findVirtual(Hello.class, "hello", MethodType.methodType(Void.class, String.class));
    
  4. 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");
    
  5. 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.

Keywords: Java reflection computer language

Added by shortkid422 on Sun, 26 Dec 2021 13:06:22 +0200