Reflective overview

What is reflection

The process of encapsulating the components of a class into other objects is called reflection. The components refer to our class’s fields, constructors, and methods.

Pros and cons of using reflection

  • advantages

    1. The class object can be operated during the program running, which increases the flexibility of the program.
    2. Decoupling, so as to improve the scalability of the program, improve the code reuse rate, convenient external call;
    3. For any class, when you know its class name, you can know all the attributes and methods of that class. For any object, one of its methods can be called.
  • disadvantages

    1. Performance issues: Java reflection contains dynamic types that cannot be optimized by the JVM, so operating through reflection is less efficient than normal.
    2. Security issues: The use of reflection requires that the program must run in an environment with no security restrictions. If the program has security restrictions, reflection cannot be used.
    3. Program robustness: Reflection allows code to perform actions that are not normally allowed, breaking the abstraction of program structure and making the abstract logical structure unrecognizable when the platform changes.

Getting and using the Class object

How to get a Class object

  1. Class. ForName (" full name ")

Source code stage, it can load the bytecode file into memory, and then return the Class object, mostly used in the configuration file, define the Class name in the configuration file, by reading the configuration file to load the Class.

  1. The name of the class. The class

Class object stage, through the class attribute of the class name to obtain, mostly used for parameter passing.

  1. Object. GetClass ()

At run time, getClass() is defined in the Object class, indicating that all classes can use this method, which is mostly used to get bytecodes for objects.

We’ll start by defining a Person class for subsequent reflection testing.

package com.cunyu;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Person
 * @date : 2021/4/7 22:37
 * @description: the Person class * /

public class Person {
    private int age;
    private String name;
    public long id;
    public long grade;
    protected float score;
    protected int rank;


    public Person(int age, String name, long id, long grade, float score, int rank) {
        this.age = age;
        this.name = name;
        this.id = id;
        this.grade = grade;
        this.score = score;
        this.rank = rank;
    }

    public Person(a) {}public int getAge(a) {
        return age;
    }

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

    public String getName(a) {
        return name;
    }

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

    public long getId(a) {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    
    public long getGrade(a) {
        return grade;
    }

    public void setGrade(long grade) {
        this.grade = grade;
    }

    public float getScore(a) {
        return score;
    }

    public void setScore(float score) {
        this.score = score;
    }

    public int getRank(a) {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    @Override
    public String toString(a) {
        final StringBuffer sb = new StringBuffer("Person{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\' ');
        sb.append(", id=").append(id);
        sb.append(", grade=").append(grade);
        sb.append(", score=").append(score);
        sb.append(", rank=").append(rank);
        sb.append('} ');
        returnsb.toString(); }}Copy the code

Once the Person Class is defined, we try to get the Class objects in three different ways and compare them to see if they are the same.

package com.cunyu;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo1
 * @date: 2021/4/7 "*@description: gets the Class object */

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException {
// The first method, class.forname (" full Class name ")
        Class class1 = Class.forName("com.cunyu.Person");
        System.out.println(class1);

// The second way, the class name.class
        Class class2 = Person.class;
        System.out.println(class2);

// The third way, object.getName ()
        Person person = new Person();
        Class class3 = person.getClass();
        System.out.println(class3);

// Compare whether three objects are the sameSystem.out.println(class1 == class2); System.out.println(class1 == class3); }}Copy the code

In the above code, you can see that the final comparison result returns two true, indicating that the Class object obtained by the above three methods is the same, and the same bytecode file (*.class) is loaded only once during a run.

The use of Class objects

Get member variables

methods instructions
Field[] getFields() Return contains an arrayFieldObject reflects all accessible public field-class objects of the class or interface represented by this
Field getField(String name) Returns aFieldObject that reflects the specified public member field class object of the class or interface that this represents
Field[] getDeclaredFields() Array returnedFieldObject reflects all field class objects declared by this represented class or interface
Field getDeclaredField(String name) Returns aFieldObject that reflects the specified declared field class object of the class or interface that this represents
  • Field[] getFields()
package com.cunyu;

import java.lang.reflect.Field;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo2
 * @date: 2021/4/7 for *@description: The use of Class objects */

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class class1 = Class.forName("com.cunyu.Person");

        Field[] fields = class1.getFields();
        for(Field field : fields) { System.out.println(field); }}}Copy the code

If you look back at the Person class, you can see that the id and grade member variables are all decorated by public, indicating that this method is used to get all member variables in the class that are decorated by public (including the parent class).

  • Field getField(String name)
package com.cunyu;

import java.lang.reflect.Field;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo2
 * @date: 2021/4/7 for *@description: The use of Class objects */

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class class1 = Class.forName("com.cunyu.Person");

        Field field1 = class1.getField("id");
        System.out.println(field1);
        Field field2 = class1.getField("age");
        System.out.println(field2);
        Field field3 = class1.getField("rank"); System.out.println(field3); }}Copy the code

From the above analysis, we can see that this method can only be used to get the public variable of the specified name in the class. For protected and private variable, this method is not available (including the parent class). To obtain or set the value of a member variable, you can use the get/set method as follows.

// If we get the Field as the id above, we can get and set the id by doing the following
/ / 1. Access
Field idField = personClass.getField("id");
Person person = new Person();
Object idValue = idField.get(person);
System.out.println("id:" + idValue);
/ / 2. Set up
idField.set(person, "1312120");
System.out.println("person:" + person);
Copy the code
  • Field[] getDeclaredFields()
package com.cunyu;

import java.lang.reflect.Field;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo2
 * @date: 2021/4/7 for *@description: The use of Class objects */

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class class1 = Class.forName("com.cunyu.Person");

        Field[] fields = class1.getDeclaredFields();
        for(Field field : fields) { System.out.println(field); }}}Copy the code

As you can see from the above results, this method can be used to get all member variables, regardless of modifiers (excluding the parent class).

  • Field getDeclaredField(String name)
package com.cunyu;

import java.lang.reflect.Field;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo2
 * @date: 2021/4/7 for *@description: The use of Class objects */

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class class1 = Class.forName("com.cunyu.Person");

        Field field1 = class1.getDeclaredField("id");
        System.out.println(field1);
        Field field3 = class1.getDeclaredField("rank");
        System.out.println(field3);
        Field field2 = class1.getDeclaredField("age"); System.out.println(field2); }}Copy the code

As you can see from the above, this method can be used to get a specified member variable, regardless of the limitations of the member variable modifier (excluding the parent class). However, when using the set and get methods to get and set private and protected member variables, you need to use setAccessible() to ignore the security check for accessing the new modifiers, otherwise the program will report an error.

Get constructor

methods instructions
Constructor<? >[] getConstructors() Return contains an arrayConstructor Object reflects all common constructor class objects of the class represented by this
Constructor < T > getConstructor (class <? >... parameterTypes) Returns aConstructor Object that reflectsConstructor The specified public class function of the class represented by the
Constructor<? >[] getDeclaredConstructors() Return a reflectionConstructorObject represents the class declarationConstructorObject is an array class
Constructor < T > getDeclaredConstructor (class <? >... parameterTypes) Returns aConstructorObject that reflectsConstructorThe specified class function of the class or interface represented by the
package com.cunyu;

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

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo3
 * @date : 2021/4/8 13:28
 * @descriptionConstruct the object to get */

public class Demo3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class personClass = Class.forName("com.cunyu.Person");

// 1. Get all constructors
        System.out.println("All constructors");
        Constructor[] constructors = personClass.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

// get the specified constructor

// Empty parameter constructor
        System.out.println("Empty parameter construction method");
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
// parameter constructor
        System.out.println("Parametric construction method");
        Constructor constructor2 = personClass.getConstructor(int.class, String.class, long.class, long.class, float.class, int.class);
        System.out.println(constructor2);

// Once you get the constructor, you can use it to create an object
        System.out.println("Empty parameter creates object");
// The first method
        Object person = constructor1.newInstance();
        System.out.println(person);
// The second method
        Object person1 = personClass.newInstance();
        System.out.println(person1);
        
        System.out.println("Create object with parameters");
        Object object = constructor2.newInstance(20."Village Rain Yao".1312020.3.99.0 F.2); System.out.println(object); }}Copy the code

  • Constructor<? >[] getConstructors()

    Similar to getting a member variable from a Class instance, this method is used to get all constructors (including the parent Class) decorated by public;

  • Constructor < T > getConstructor (class <? >... parameterTypes)

This method is used to get the constructor (including the parent class) that public modifies after a specified parameter type.

  • Constructor<? >[] getDeclaredConstructors()

This method is used to get all constructors modified by public (excluding the parent class);

  • Constructor < T > getDeclaredConstructor (class <? >... parameterTypes)

This method is used for constructors (excluding parent classes) that are modified by public after taking a specified parameter type.

Once we have the constructor, we can use the newInstance() method to create instances of the class. In particular, if our constructor has no arguments, we can construct instances directly using class.newinstance ().

Get member method

methods instructions
Method[] getMethods() Returns all public method class objects that contain an array of method objects reflecting the class or interface represented by them, including those declarations inherited from the class or interface and those inherited from the superclass and superinterface
Method getMethod(String name, class <? >... parameterTypes) Returns a method object that reflects the specified public member method class object of this represented class or interface
Method[] getDeclaredMethods() Returns all declared methods of a class or interface that contain the reflection of an array method object, represented by this class object, including public, protected, default (package) access, and private methods, but not inherited methods
Method getDeclaredMethod(String name, class <? >... parameterTypes) Returns a method object that reflects the specified declared method class object of this represented class or interface
package com.cunyu;

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

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo4
 * @date: 2021/4/8 they *@descriptionThe: member method gets */

public class Demo4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class personClass = Class.forName("com.cunyu.Person");

// Get all public member methods
        System.out.println("Get all member methods");
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

// Get the method of the specified name
        System.out.println("Method to get the specified name");
        Method getAgeMethod = personClass.getMethod("getAge");
        System.out.println(getAgeMethod);

// Execute method
        Person person = new Person(20."Village Rain Yao".1312020.3.99.0 F.2);
        int age = (int) getAgeMethod.invoke(person); System.out.println(age); }}Copy the code

  • Method[] getMethods()

Member methods (including the parent class) that are used to get all the public modifiers of the current class.

  • Method getMethod(String name, class <? >... parameterTypes)

Gets a member method (including the parent class) that is modified by a specified name public of the current class.

  • Method[] getDeclaredMethods()

Member methods used to get all the public modified member methods of the current class (excluding the parent class).

  • Method getDeclaredMethod(String name, class <? >... parameterTypes)

A member method (excluding the parent class) that gets one of the specified names public of the current class.

Once we have a member method of the class, if we want to execute a method, we can use the invoke() method to execute that method.

Get the name of the class

package com.cunyu;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Demo5
 * @date : 2021/4/8 14:06
 * @description: Gets the class name */

public class Demo5 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = newPerson(); Class personClass = person.getClass(); String className = personClass.getName(); System.out.println(className); }}Copy the code

  • String getName()

GetName () : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName() : getName()

Reflection instance

Suppose we have a requirement that we can create objects of any class and execute its methods without changing the code of the class.

At this point, we can achieve this effect by using the configuration file + reflection, which is the basis of the framework we are using now. When we use reflection, we just need to modify the content of the configuration file to achieve the corresponding function without changing the code.

Suppose we have two classes, Student and Teacher, defined as follows;

package com.cunyu;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Teacher
 * @date : 2021/4/8 15:15
 * @description: Teacher */

public class Teacher {
    private String name;
    private int age;

    public void teach(a) {
        System.out.println("Teaching..."); }}Copy the code
package com.cunyu;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : Student
 * @date: * 2021/4/8 struck@description: Student */

public class Student {
    private String name;
    private float score;

    public void study(a) {
        System.out.println("Good good study, day day up..."); }}Copy the code

To implement our requirements, the following steps are usually required:

  1. The full class name of the object to be created and the method to be executed are configured in the configuration file;

Prop.properties, the main contents of which include the className and methodName properties, representing the full className of the class and the name of the method to be called, respectively. A concrete example is the following, representing a class named Student and a method named study.

className=com.cunyu.Student
methodName=study
Copy the code
  1. Then load the read configuration file in the main method;
// Create a configuration file object
Properties properties = new Properties();
// Load the configuration file
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("prop.properties");
properties.load(inputStream);

// Get the data defined in the configuration file
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
Copy the code
  1. Use reflection technology to load the class into memory;
// Load into memory
Class name = Class.forName(className);
Copy the code
  1. Then usenewInstance()Method to create an object;
// Create an instance
Object object = name.newInstance();
Copy the code
  1. And finally, useinvoke()Method to execute method;
// Get and execute methods
Method method = name.getMethod(methodName);
method.invoke(object);
Copy the code

Putting the whole process together is:

package com.cunyu;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

/ * * *@author : cunyu
 * @version : 1.0
 * @className : ReflectTest
 * @date: 2021/4/8 and *@description: * / test

public class ReflectTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
// Create a configuration file object
        Properties properties = new Properties();
// Load the configuration file
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream("prop.properties");
        properties.load(inputStream);

// Get the data defined in the configuration file
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

// Load into memory
        Class name = Class.forName(className);

// Create an instance
        Object object = name.newInstance();

// Get and execute methodsMethod method = name.getMethod(methodName); method.invoke(object); }}Copy the code

At this point, we just need to change the configuration in the prop.properties configuration file to output different results;

conclusion

All right, thank you for your patience. If you found this article helpful, give me a like!

Finally, for the knowledge of the article there is a mistake or lack of place, please forgive me, welcome to comment on the message to me ~