java reflection explanation and reflection optimization

Posted by borris_uk on Sat, 18 Sep 2021 12:02:05 +0200

Reflection is an important part of java language. Reflection can dynamically execute and access classes, methods and fields during operation, which will greatly improve the flexibility of the framework. Therefore, like many open source frameworks, reflection is widely used to dynamically generate objects, such as spring bean s and mybatis mapper. But the performance of reflection has been criticized. How many ways to create objects in java? 1. Use new keyword 2. Use clone method 3. Use deserialization 4. Use reflection 5. Use Unsafe

1. A small demo that instantiates an object using reflection and calls the methods in the object
1.1 define a Student object

/**
 * @Author feng ye
 * @Date 2021/6/30 0:48
 * @Description
 */
public class Student {
    public void toSleep(){
        System.out.println("toSleep Method was executed...");
    }
}
Copy code

1.2 define a property file whose content is the fully qualified name of the class and the methods in the class

1.3 read the information of the configuration file, instantiate the Student object using reflection and call the toSleep method

/**
 * @Author feng ye
 * @Date 2021/6/30 0:41
 * @Description
 */
public class ReadSource {

    public static void main(String[] args) throws Exception{
        //  You can create objects of any class and execute any method
        //  Premise: you cannot change any code of this class. You can create objects of any class and execute any method
        //1. Load configuration file
        //1.1 create Properties object
        Properties pro = new Properties();
        //1.2 load the configuration file and convert it into a collection
        //1.2.1 get the configuration file under the class directory
        ClassLoader classLoader = ReadSource.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        //2. Obtain the data defined in the configuration file
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //3. Load this class into memory
        Class cls = Class.forName(className);
        //4. Create object
        Object obj = cls.newInstance();
        //5. Get method object
        Method method = cls.getMethod(methodName);
        Method[] methods = cls.getMethods();
        System.out.println("methods.length :"+ methods.length);
        for (Method m : methods){
            System.out.println("Class name:"+cls.getSimpleName()+" ,Method name"+m.getName());
        }
        //6. Implementation method
        method.invoke(obj);
    }
}
Copy code

Execution results:

The above is how to use reflection and spi to dynamically generate objects. We only need to replace the class name and method name in the configuration file

2. Explanation of Class object of reflection
There are three ways to get a class object. Although they are different, they all get the same class object. Because the class file will only be loaded once by the jvm

* Class Object function:
   * Get features:
      1. Get member variables
         * Field[] getFields() : Get all public Decorated member variable
         * Field getField(String name)   Gets the of the specified name public Decorated member variable

         * Field[] getDeclaredFields()  Gets all member variables, regardless of modifiers
         * Field getDeclaredField(String name)
      2. Get constructors
         * Constructor<?>[] getConstructors()
         * Constructor<T> getConstructor(class<?>... parameterTypes)

         * Constructor<T> getDeclaredConstructor(class<?>... parameterTypes)
         * Constructor<?>[] getDeclaredConstructors()
      3. Get member methods:
         * Method[] getMethods()
         * Method getMethod(String name, class<?>... parameterTypes)

         * Method[] getDeclaredMethods()
         * Method getDeclaredMethod(String name, class<?>... parameterTypes)

      4. Get full class name
         * String getName()
Copy code

3. Reflect the operation on the file object
3.1 define a Person class

```
public class Person {

    public String a;
    protected String b;

    String c;
    String d = "I am d";

    private int age;
    private String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Person() {
    }

    private Person(String name) {
        this.name = name;
    }

    public void show() {
        System.out.println("show Method is executed");
    }

    private void show2() {
        System.out.println("Private show2 Method is executed");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "a='" + a + ''' +
                ", b='" + b + ''' +
                ", c='" + c + ''' +
                ", d='" + d + ''' +
                ", age=" + age +
                ", name='" + name + ''' +
                '}';
    }

    public void eat() {
        System.out.println("eat...");
    }

    public void eat(String food) {
        System.out.println("eat..." + food);
    }

    private void sum(Integer num) {
        System.out.println("sum Method was executed..." + num);
    }
}
```
Copy code

3.2 use reflection to access properties without permission in the class and assign values to properties

/**
 * @Author feng ye
 * @Date 2021/6/30 0:23
 * @Description Use reflection to obtain the member variable [attribute] of Class object
 * It can be assigned and valued; Including different modifications, which can be aligned [public,protected,private]
 */
public class ReflectDemo02 {

    /**
     * Class Object function:
     * Get features:
     * Get member variables
     * Field[] getFields()
     * Field getField(String name)
     * Field[] getDeclaredFields()
     * Field getDeclaredField(String name)
     */
    public static void main(String[] args) throws Exception {

        //0. Get the Class object of Person
        Class personClass = Person.class;
        /*
             1. Get member variables
                 * Field[] getFields()
                 * Field getField(String name)

                 * Field[] getDeclaredFields()
                 * Field getDeclaredField(String name)
         */
        //1.Field[] getFields() gets the member variables of all public modifiers
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println("Traverse to get all public Decorated member variable field: " + field);
        }

        //2.Field getField(String name)
        Field a = personClass.getField("a");
        //Gets the value of the member variable a
        Person p = new Person();
        Object value = a.get(p);
        System.out.println("obtain person Properties of a name: "+value);
        //Set the value of a
        a.set(p, "Zhang San");
        System.out.println("set up person Properties of a Value of: " + p);

        System.out.println("#############Separator############");

        //Field [] getdeclaraedfields(): get all member variables, regardless of modifiers
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //Enable brute force access to access the private properties of the class
            declaredField.setAccessible(true);
            Object a1 = declaredField.get(p);
            System.out.println("--------------->a1: " + a1);
            System.out.println("--------------->declaredField: " + declaredField);
        }
        //Field getDeclaredField(String name)
        Field d = personClass.getDeclaredField("d");
        //Ignore security checks for access modifier
        d.setAccessible(true);//Violent reflex
        Object value2 = d.get(p);
        System.out.println("obtain person Properties in class d Value of: "+value2);

    }

}
Copy code

results of enforcement

4. Methods in launch access class

public class ReflectDemo04 {

    /**
     * Class Object function:
     * Get member methods:
     * Method[] getMethods()
     * Method getMethod(String name, Class<?>... parameterTypes)
     * Method[] getDeclaredMethods()
     * Method getDeclaredMethod(String name, Class<?>... parameterTypes)
     *
     * //Get class name
     * String getName()
     */
    public static void main(String[] args) throws Exception {

        //0. Get the Class object of Person
        Class personClass = Person.class;
        //Gets the method with the specified name
        Method eat_method = personClass.getMethod("eat");
        Person p = new Person();
        //Execution method
        eat_method.invoke(p);

        Method eat_method2 = personClass.getMethod("eat", String.class);
        //Execution method
        eat_method2.invoke(p, "meal");

        System.out.println("---------------Separator 1---------------");

        //Gets the method of all public modifiers
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println("Get all public Modification methods, methodName: "+method);
        }

        System.out.println("---------------Separator 2---------------");

        //Get the sum method of private decoration
        Method sum = personClass.getDeclaredMethod("sum",Integer.class);
        sum.setAccessible(true);
        sum.invoke(p,1);

    }
Copy code

Execution results:

5. Why does reflection slow down
The following is the original words of oracle's official website:
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
The main idea is that the type of reflection is dynamically resolved, which will make it impossible for the JVM to implement some specific optimizations (specifically, what we often call JIT optimization). In performance sensitive and frequently invoked methods, reflection should be avoided as much as possible.

5.1 static loading and dynamic loading: the following is a clssload_ program written in notePad + + Java file, and then try to use cmd to javac (separate screenshot)

Static loading: the java file we wrote is compiled into a class bytecode file during compilation. Because Dog is loaded statically, if the class does not exist, an exception [classNofoundException] will be thrown

Dynamic loading: Person is dynamic loading, so even when the Person does not exist, there will be no error in the compilation stage. An error will be reported only when case "2" is executed and the Person class is dynamically loaded.

Conclusion: a conclusion can be drawn (why the reflection is slow and affects the performance). Because the bytecode file of the object is loaded into the jvm only when the reflection is dynamically loaded. Moreover, accessing reflection related attributes will lead to time-consuming judgment such as security check. [dynamic loading can be understood as lazy loading of java objects, because some things need to be done in the process of dynamic loading, so it is slow]

Optimization of reflection:


Author: Chuxin never forgets 976
Link: https://juejin.cn/post/7007410196330840071
Source: Nuggets
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, and for non-commercial reprint, please indicate the source.

Topics: Java