• What is reflection?

The Java reflection mechanism allows you to know all the properties and methods of any class in the running state. For any object, you can call any of its methods and properties; This ability to dynamically retrieve information and invoke object methods is called the Reflection mechanism of the Java language.

Reflection can perform all functions of any class at runtime, such as calling methods, modifying the values of member variables, and calling constructors. Reflection can also perform violent reflection even if it is private. Sorry ~ reflection can do whatever it wants.

  • Gets the bytecode Class

To reflect a Class, you must first get the bytecode Class, and there are three ways to get the bytecode

       // The first method
       Student student = new Student();
       Class<? extends Student> studentClass1 = student.getClass();

       // The second method
       Class<Student> studentClass2 = Student.class;
       
       // The third way
       try{ Class<? > studentClass3 = Class.forName("senior.reflection.Student");
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       }
Copy the code
  • Gets a member variable of the class

public class Student {
    private int age = 18;
    private String name = "Zhang";
    public String gender = "Male";
}
Copy the code

  1. GetFields (): Only public qualified member variables can be retrieved
  2. GetField (String name): Gets a member variable by its name, which can only be public
  3. GetDeclaredFields (): Retrieves all member variables
  4. GetDeclaredField (String name): Gets a member variable by its name, any modifier
        Student student = new Student();
        Class<? extends Student> studentClass = student.getClass();

        //getFields()
        for (Field field : studentClass.getFields()) {
            System.out.println("getFields(): " + field.getName());
        }

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

        //getDeclaredFields(**)
        for (Field field : studentClass.getDeclaredFields()) {
            System.out.println("getDeclaredFields(): " + field.getName());
        }

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

        //getDeclaredField(String name)
        Field age1 = studentClass.getDeclaredField("age");
        System.out.println("getDeclaredField(String name): "+age1.getName());

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

        //getField(String name)
        Field age2 = studentClass.getField("age");
        System.out.println("getField(String name): " + age2.getName());

Copy the code

Running results:

  • Modifies and gets the value of a member variable

public class Student {
    private int age = 18;
    private String name = "Zhang";
    public String gender = "Male";
}
Copy the code

Private int age = 18

        Student student = new Student();
        Class<? extends Student> studentClass = student.getClass();

        Field age = studentClass.getDeclaredField("age");

        // The age before modification
        int beforeAge = age.getInt(student);
        System.out.println("Age before modification:"+beforeAge);

        // Change age to 38
        age.setInt(student, 38);

        // New age
        int afterAge = age.getInt(student);
        System.out.println("Age:"+afterAge);

Copy the code

Running results:

Didn’t it say that private can also operate? Why an error…. Don’t panic! It’s a violent reflex!

age.setAccessible(true);
Copy the code

This line of code can reflect private member variables, constructors, normal methods, etc. In essence, reflection does not check permissions, so there is no error when operating on private member variables. This is called “violent reflection”.

Now let’s add the violent reflex and do it again:

        Student student = new Student();
        Class<? extends Student> studentClass = student.getClass();


        Field age = studentClass.getDeclaredField("age");
        
        // Violent reflex
        age.setAccessible(true);

        // The age before modification
        int beforeAge = age.getInt(student);
        System.out.println("Age before modification:"+beforeAge);

        // Change age to 38
        age.setInt(student, 38);

        // New age
        int afterAge = age.getInt(student);
        System.out.println("Age:"+afterAge);

Copy the code

Running results:

  • Gets the constructor of the class

  1. GetConstructors (): Constructor that can only get public modifications
  2. getConstructor(Class
    … ParameterTypes: a constructor that gets a public modifier from the bytecode of the parameter
  3. GetDeclaredConstructors (): Get all constructors
  4. getDeclaredConstructor(Class
    … ParameterTypes: Gets the constructor from the bytecode of the parameter, any modifier
	public class Student {
	    public Student(a) {
	        System.out.println("Empty parameter constructor called");
	    }
	
	    // Private methods
	    private Student(int age, String name) {
	        System.out.println("The multi-argument private constructor was called:" + age + ""+ name); }}Copy the code

        // Get the bytecode Class using the Class nameClass<? > studentClass = Class.forName("senior.reflection.Student");

        //getConstructors()
        for(Constructor<? > constructor : studentClass.getConstructors()) { System.out.println("getConstructors(): "+constructor);
        }

        //getConstructor()
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); Constructor<? > constructor = studentClass.getConstructor(); Student student = (Student) constructor.newInstance(); System.out.println("getConstructor(): "+constructor);

        //getDeclaredConstructors()
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
        for(Constructor<? > declaredConstructor : studentClass.getDeclaredConstructors()) { System.out.println("getDeclaredConstructors(): "+declaredConstructor);
        }

        //getDeclaredConstructor()
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); Constructor<? > declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class);
        System.out.println("getDeclaredConstructor(): "+declaredConstructor);
        // Violent reflection is used because it is a private constructor
        declaredConstructor.setAccessible(true);
        // Pass the argument to the constructor to create the object
        Student student = (Student) declaredConstructor.newInstance(28."Bill");
Copy the code

Running results:

  • Instantiate an object

Now that the constructor is available, we can instantiate the object through the constructor

  • Instantiate an object with an empty parameter constructor:

	public class Student {
	    public Student(a) {
	        System.out.println("Empty parameter constructor called"); }}// Get the bytecode Class using the Class nameClass<? > studentClass = Class.forName("senior.reflection.Student"); Constructor<? > constructor = studentClass.getConstructor(); Student student = (Student) constructor.newInstance();Copy the code
  • Instantiate the object with the multi-parameter constructor:

	public class Student {
	    // Private methods
	    private Student(int age, String name) {
	        System.out.println("The multi-argument private constructor was called:" + age + ""+ name); }}// Get the bytecode Class using the Class nameClass<? > studentClass = Class.forName("senior.reflection.Student"); Constructor<? > declaredConstructor = studentClass.getDeclaredConstructor(int.class, String.class);
    // Violent reflection is used because it is a private constructor
    declaredConstructor.setAccessible(true);
    // Pass the argument to the constructor to create the object
    Student student = (Student) declaredConstructor.newInstance(28."Bill");
Copy the code
  • Gets and calls the member methods of the class

  1. GetMethods (): Only public qualified member methods can be obtained
  2. ParameterTypes getMethod(String name, Class[] parameterTypes): public accessorized member method. The first parameter is the method name. The second parameter is the Class bytecode of the parameter type
  3. GetDeclaredMethods (): Retrieves all member methods
  4. ParameterTypes getDeclaredMethod(String name, Class[] parameterTypes): getDeclaredMethod(String name, Class[] parameterTypes): getDeclaredMethod(String name, Class[] parameterTypes): Gets all matched member methods

SetAge () and getAge() are public methods setNameAndGender() and getNameAndGender() are private

	public class Student {
	    private int age = 18;
	    private String name = "Zhang";
	    public String gender = "Male";
	
	    public int getAge(a) {
	        return age;
	    }
	
	    public void setAge(int age) {
	        this.age = age;
	    }
	
	    /** * private method */
	    private String getNameAndGender(a) {
	        return name;
	    }
	
	    /** * private method */
	    private void setNameAndGender(String name,String gender) {
	        this.name = name;
	        this.gender = gender; }}Copy the code

Reflection gets and calls methods:


      // Get the bytecode Class using the Class nameClass<? > studentClass = Class.forName("senior.reflection.Student");
      Object student = studentClass.newInstance();

      //getMethods()
      for (Method method : studentClass.getMethods()) {
          System.out.println("getMethods(): "+method.getName());
      }

      //getDeclaredMethods()
      System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
      for (Method method : studentClass.getDeclaredMethods()) {
          System.out.println("getDeclaredMethods(): "+method.getName());
      }

      //getMethod()
      System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
      Method setAge = studentClass.getMethod("setAge".int.class);
      // Invoke manipulates method arguments 1: the object to operate on 2: the parameter to pass in
      setAge.invoke(student,48);

      Method getAge = studentClass.getMethod("getAge");
      // The return value of invoke is the return value of the method
      Object age = getAge.invoke(student);
      System.out.println("GetMethod () gets the age:"+age);

      //getMethod()
      System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
      Method setNameAndGender = studentClass.getDeclaredMethod("setNameAndGender", String.class, String.class);
      // Violent reflex
      setNameAndGender.setAccessible(true);
      // Invoke manipulates method arguments 1: the object to operate on 2: the parameter to pass in
      setNameAndGender.invoke(student,"Fifty"."Female");

Copy the code

Running results:

  • conclusion

  1. The getDeclaredXxx() method retrieves all information but does not contain information about the inherited parent
  2. The getXxx() method only gets the public modifier information, but it also contains the inherited parent’s public information
  3. Private information can be manipulated by violent reflection setAccessible(true)
  4. Instantiate objects using class.newinstance ()
  • How to store strings in an ArrayList?

Now that we’re done with reflection, it should be pretty easy

  1. Get the add method of the list by reflection
  2. Pass arguments to the Add method via invoke
  3. Print the data for the list
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Create an array of type Integer
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);

        // Get the add method of the list by reflection
        Method add = list.getClass().getMethod("add", Object.class);
        // Use invoke to pass parameters to a method
        add.invoke(list,"I'm a string");

        for(Object item : list) { System.out.println(item); }}Copy the code

Running results: