Reflection in JAVA

definition

The reflection mechanism of Java is to know all the properties and methods of any class in the running state; For Ren
An object can call any of its methods and properties. Since we can get it, we can modify some type information; This function of dynamically obtaining information and dynamically calling object methods is called the reflection mechanism of java language.

Purpose (understand)

1. In the process of daily third-party application development, we often encounter that a member variable, method or attribute of a class is private or only corresponding to the system
With open, you can use Java's reflection mechanism to obtain the required private members or methods through reflection.
2. The most important use of reflection is to develop various general frameworks. For example, in spring, we hand over all class beans to the spring container for management, regardless of
Is it XML configuration Bean or annotation configuration? When we get beans from the container for dependency injection, the container will read the configuration, and what is given in the configuration is the class information. Spring needs to create those beans according to this information, and spring will dynamically create these classes.

Reflection basic information

Many objects in Java programs have two types at runtime: runtime type (RTTI) and compile time type, such as Person p = new Student(); In this code, p is of type Person at compile time and Student at run time. The program needs to find the real information of objects and classes at run time. By using the reflection program, we can determine which classes the object and class belong to.

Reflection related classes (important)

Class (origin of reflection mechanism)

Class help documentation An entity representing a class that represents classes and interfaces in a running Java application
Java files (also known as source files) are compiled and generated Class file (also known as bytecode file, binary file), the JVM needs to interpret it at this time Class file, the compiled Java file Class is also parsed by the JVM into a class object, which is Java lang.Class . In this way, when the program is running, each java file will eventually become an instance of the class object. By applying the reflection mechanism of Java to this instance, we can obtain or even add and change the properties and actions of this class to make this class a dynamic class

Note: for example, a Person class will be called after compilation Class file, which will be parsed into a class object after loading into the jvm, but if it is multiple instance objects about the Person class, such as Person
p1 = new Person();Person p2 = new Person();, Finally, there is still only one Class object

Relevant methods in Class (the use method of the method is in the following example)

(important) commonly used methods to obtain class related information

(important) commonly used methods to obtain properties related to classes (the return value of the following methods is Field related)

(understand) get the methods related to annotations in the class

(important) get the constructor related methods in the class (the return value of the following methods is Constructor related)

(important) get the method related to the method in the class (the return value of the following method is Method related)

Reflection example

Three ways to get Class objects

Before reflection, the first step we need to do is to get the Class object of the Class currently to be reflected, and then achieve the purpose of reflection through the core method of the Class object, that is, for any Class in the running state, we can know all the properties and methods of the Class; For any object, we can call any of its methods and properties. Since we can get it, we can modify some type information.

First, use class Forname ("full pathname of the class"); Static method.
Premise: the full pathname of the class has been specified

Second, use class method.
Note: it is only applicable to classes that have been explicitly operated before compilation

Third, use the getClass() method of the class object

Code example

package fanshe;

class Student{
    //Private attribute name
    private String name = "bit";
    //Public attribute age
    public int age = 18;
    //Construction method without parameters
    public Student(){
        System.out.println("Student()");
    }

    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }

    private void eat(){
        System.out.println("i am eat");
    }

    public void sleep(){
        System.out.println("i am pig");
    }

    private void function(String str) {
        System.out.println(str);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class TestDemo {


    public static void main(String[] args) throws ClassNotFoundException {
        /*1.
          It is obtained through the forName() static method of Class object, which is used most,
          However, ClassNotFoundException may be thrown

          When using forName, note that the full path of our class is used in double quotation marks. If there is a package, the path of the package needs to be added. If it is a class directly under the src package, just write the class name directly
        */

        Class<?> c1 = Class.forName("fanshe.Student");

        /*
        2.Directly through the class name Class, this method is the most safe and reliable, and the program performance is higher
        This means that any class has an implicit static member variable class
        */
        Class<?> c2 = Student.class;

        /*
        3.Get Class object through getClass
         */
        Student s = new Student();
        Class<?> c3 = s.getClass();


        //A Class will only have one Class instance in the JVM, that is, the Class we obtained above
        //The output result is class fanshe Student
        System.out.println(c1);
        //The output result is class fanshe Student
        System.out.println(c2);
        //The output result is class fanshe Student
        System.out.println(c3);

        c1,c2,c3 conduct equals Comparison, found that they are all true
        System.out.println(c1.equals(c2));
        System.out.println(c1.equals(c3));
        System.out.println(c2.equals(c3));
    }
}

Use of reflection

Next, we start to use reflection. We still reflect the Student class above and write the logic of reflection into another class for understanding:

Note: all reflection related packages are in import Java Lang.reflect package.
Note: our ReflectClassDemo class and our Student class are in the same package, which is written in the above code

Code example

package fanshe;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author SongBiao
 * @Date 14:43
 */
public class ReflectClassDemo {
    /*
    Note that the student class is a class with default permissions written in the same package. The full path of the student class here is fanshe Student
    */


    /*
    newInstance method
    The output result of the method is:
    Student()
    Student{name='bit', age=18}
     */
    public static void reflectNewInstance() {
        try {
            //1. Get the Class object of Student Class and pay attention to the path
            Class<?> cl = Class.forName("fanshe.Student");
            //2. Create an instance object of Student class
            Student student = (Student) cl.newInstance();
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }




    /*
    Reflection private construction method shields the content to obtain public construction method
     */

    public static void reflectPrivateConstructor() {
        try {
            //1,
            Class<?> cl = Class.forName("fanshe.Student");


            /*
            //2,getConstructor The construction method without parameters is obtained
            Constructor<?> constructor = cl.getConstructor();
            //This is to construct objects by construction method
            Student student = (Student) constructor.newInstance();
            System.out.println(student);

            The output result is:
            Student()
            Student{name='bit', age=18}
            */


            /*
              getConstructor Only public constructors can be obtained
              getDeclaredConstructor:What you can get is the construction methods of all types (public or private)
              In fact, it can be noted that when we only want to obtain the public, we don't add Declared. If we want to obtain both private and public, we add Declared
             */


            //For example, the parameterized constructor in the Student class is a private constructor. When we want to obtain its object, we can only use the getdeclaraedconstructor method, not the getConstructor method
            Constructor<?> constructor =
                    cl.getDeclaredConstructor(String.class, int.class);
            //In the future, when reflecting private things, if you want to modify them: for example, if we don't add setAccessible(true) now; In this sentence, an error will be reported in the following newInstance
            //The reason is that our parametric construction method in Student class is private permission, so permission statement is required to modify its parameter value
            constructor.setAccessible(true);
            //When you use newInstance, you can pass in the parameter, which is equivalent to modifying the parameter value in the original private method
            Student student = (Student) constructor.newInstance("gaobo", 18);


            /*
            The output result is:
            Student(String,name)
            Student{name='gaobo', age=18}
             */
            System.out.println(student);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static void reflectPrivateConstructor1() {
        try {
            //1,
            Class<?> cl = Class.forName("fanshe.Student");

            //2. Gets a constructor without parameters
            Constructor<?> constructor = cl.getConstructor();
            //The output result is public fan he Student()
            System.out.println(constructor);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }


    /*
    Reflection private attribute: at this time, we want to get the private attribute name inside the Student class through reflection outside the class and modify it. What should we do?
     */

    public static void reflectPrivateField() {
        try {
            //1,
            Class<?> cl = Class.forName("fanshe.Student");

            //At this time, if we want to modify the private attribute name in another class, we need to use the getdeclaraedfield method to get it first
            Field field = cl.getDeclaredField("name");
            //Grant modification permission
            field.setAccessible(true);

            //Get Class object
            Student student = (Student) cl.newInstance();
            //Output the situation before modification
            /*
            The results that should be output are:
            Student()
            Student{name='bit', age=18}
             */
            System.out.println(student);

            //Modify the value of the original private attribute name to gaobo
            field.set(student, "gaobo");

            //Output the modified situation
            /*
            The results that should be output are:
            Student()
            Student{name='gaobo', age=18}
             */
            System.out.println(student);

            //The modified attribute value obtained is gaobo
            System.out.println(field.get(student));


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }


    /*
     Reflection private method
     */
    public static void reflectPrivateMethod() {
        try {
            //1,
            Class<?> cl = Class.forName("fanshe.Student");
            //2. Note that in getDeclaredMethod, one is the method name and the other is the method parameter type class
            //For example, at this time, we want to reflect the private method function method in the Student class
            Method method = cl.getDeclaredMethod("function", String.class);

            //Grant modification permission
            method.setAccessible(true);
            //Or get the instance object of the Student class
            Student student = (Student) cl.newInstance();

            //Use the invoke method to add parameters to our private function method
            method.invoke(student, "I am the parameter!");


            /*
            The final output of the reflectPrivateMethod method is:
            Student()
            I am the parameter!

             */

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
       /*
        reflectNewInstance();
        reflectPrivateConstructor();
        reflectPrivateField();
       */
        reflectPrivateMethod();
    }

}

Advantages and disadvantages of reflection

advantage

1. For any class, you can know all the properties and methods of this class; Any method of any object can be called
2. Increase the flexibility and expansibility of the program, reduce the coupling and improve the adaptive ability
3. Reflection has been used in many popular frameworks, such as Struts, Hibernate, Spring and so on.

shortcoming

1. Using reflection will have efficiency problems. It will reduce the efficiency of the program. See here for details: Click here to enter the link
2. Reflection technology bypasses the technology of source code, which will bring maintenance problems. Reflective code is more complex than the corresponding direct code.

Key summary

1. The meaning of reflection
2. Several important classes of reflection: Class, Field, Method and Constructor
3. Learn to make rational use of reflection and be sure to use it in a safe environment.

Keywords: Java reflection JavaSE

Added by kaumilpatel on Thu, 03 Feb 2022 02:00:14 +0200