Let's talk about reflection in Java, which is easy to understand

preface:

Today, I simply learned the lower reflection. The bullet screen at station B said that I couldn't understand it. I studied it and found that the reason why I couldn't understand it was that there were a lot of contents, but I couldn't separate the school. Another point was that the teacher spoke a little abstract, so I explained it in easy to understand words during the summary in the evening to deepen my memory.

What is reflection

definition

Reflection is a technology that dynamically obtains all parts of a class during the running of a program. A little more detail is to encapsulate each part of the class into other objects.

explain

| these two sentences are abstract and need to be carefully analyzed. For example, we define a Student class. The main parts of the class are attributes, construction methods and common methods. Of course, there is toString. When I define here, different access modifiers are used for attributes, construction methods and common methods. Please pay attention to them and they will be used later. Just take a brief look at the code and read the following articles directly

package cn.itcast.person;
/**
 * Student class
 */
public class Student {
    //attribute
    public String name;
    protected int age;
    String sex;
    private int height;

    /**
     * Construction method
     */
    public Student() {
    }

    public Student(String name, int age, String sex, int height) {

        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
    }
    private Student(String name){
        this.name = name;
    }

    //Common method
    public void study() {
        System.out.println("study");
    }
    private void sleep(){
        System.out.println("sleep");
    }
    public void eat(int i ){
        System.out.println("Yes"+i+"Bowl rice");
    }

    //get/set method
    public String getName() {
        return name;
    }

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


    //
    public int getAge() {
        return age;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

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


Then we can define a test class to create student objects and call methods.

package cn.itcast.person;

/**
 * Student testing
 */
public class StudentTest {
    public static void main(String[] args) {
        Student s = new Student();
        s.study();
    }
}

This is how we usually write code. In fact, there is another step between these two steps, that is, loading the class we write into memory, which is automatically completed by the virtual machine. This step is what most people don't understand. The file we write is saved as a. java. Type file. After compilation, it is a. Class type file, and then through the class loader, Turn the whole class into a class object, as shown in the following figure

It can be imagined that there is a Class with various types of attributes, as follows

public class Class1 {//Write Class1 as the keyword, and class as the keyword,
    public Field[] shuxing ;//Is the attribute
    public Constructor[] gouzaofangfa;//Construction method
    public Method[] fangfa;//Common method

    //The construction method omits...

    //Omit in the ordinary way...
}

Then create the class object studentclass, which is the class object corresponding to the student class. What does it mean,

This object has an attribute of field array type: public Field[] shuxing; This array contains all the attributes of the student class, that is, all the attributes of the student class (name, age, gender) are of type field in the class object!!

There is also a constructor array type attribute: public Constructor[] gouzaofangfa; This array contains all the construction methods of the student class, that is, all the construction methods of the student class are of type constructor in the class object!!

There is also a method array type attribute public Method[] fangfa; This array holds all the ordinary methods of the student class. Similarly, the methods in the class object are of type method

Note that this is easy to understand. In fact, it is not stored in this way, but it is difficult to understand this paragraph if it is not said in this way
It doesn't matter if you don't understand this paragraph. It's easier to understand how to reflect after reading it.

Why reflection (the function of reflection)

The dynamic acquisition of each component of the class is the soul of framework design. A case will be used later to explain why it is a soul

How

1 get Class object

There are three methods, corresponding to the three processes of class operation
| 1. The corresponding class of Class.forName ("full pathname") has just been written and has not been loaded into memory
| 2. The class name. Class correspondence has been loaded and the object has not been generated. This is called as an attribute of the class
| 3, object. getclass(); The object is generated, and the method is called with the object. The code is as follows

public class ReflectTest1 {
    public static void main(String[] args) throws Exception {
        /**
         * Get the class object corresponding to the class
         * 1,Class.forName()
         * 2,Class name.class
         * 3,Object. getclass()
         */
        //1,Class.forName()
        Class sclass1 = Class.forName("cn.itcast.person.Student");
        //2. Class name.class
        Class sclass2 = Student.class;
       // 3. Object. getclass(), create an object of student class first
        Student s = new Student("Guo Degang", 45, "male", 170);
        Class sclass3 = s.getClass();

        System.out.println(sclass1);
        System.out.println(sclass2);
        System.out.println(sclass3);

        System.out.println(sclass1 == sclass2);
        System.out.println(sclass1 == sclass3);
}

In this way, we have obtained the class object corresponding to the Student class. It must be noted here that these three objects are the same. In fact, there is only one in memory. The above five outputs are:

What's the use of getting a class object? We still don't understand how reflection dynamically obtains all parts of the class when the program is running. To know how to obtain, first of all, how many main parts of the class? Three, attributes, construction methods, common methods, of course, there are also class names, package names, etc. Let's talk about these three main parts,

get attribute

| to obtain the attribute is to obtain the attribute value of a student object. There are two steps:

1. Get the attribute name first

| four methods are given in code form:

public class ReflectTest1 {
    public static void main(String[] args) throws Exception {
        /**
         * First, get the class object of the student class
         */

        Student s = new Student("Guo Degang", 45, "male", 170);
        Class sclass3 = s.getClass();
       
        /**
         * Get the property and use the method called by the class object
         * 1 Gets the property getfile() of the specified public
         * 2 Get all public properties getfiles()
         *
         * 3 Gets the property of the specified declaration 	 getDeclaredField()
         * 4 Get all declared properties getdeclaraedfields()
         */

         /*1 Get the property getfile() of the specified public, except name,
         	The other three will report errors because they are not public modified
         */
        Field name = sclass1.getField("name");
        Field age = sclass1.getField("age");
        Field sex = sclass1.getField("sex");
        Field height = sclass1.getField("height");

		//2 get all public attributes getfiles()
        Field[] fields = sclass1.getFields();
        
		//3 get the properties of the specified declaration 	 getDeclaredField()
        Field name1 = sclass1.getDeclaredField("name");
        Field age1 = sclass1.getDeclaredField("age");
        Field sex1 = sclass1.getDeclaredField("sex");
        Field height1 = sclass1.getDeclaredField("height");
        
		//4 get all declared properties getdeclaraedfields()
        Field[] declaredFields = sclass1.getDeclaredFields();
		
       

Explanation:
getField ("property name") is the property name of the specified public modification. If it is not public modification, it will not work. In the above code, except that the name is public, the other three will report errors,
getFields(); This is to get the property names of all public modifications, and return an array that can be traversed.

declared means declaration, which is available in the student class, whether private or not, as long as you are in the student class, so getdeclaredField ("property name") can obtain the private property name, and those with s also return an array. You can output them to try.

Find the property value of the corresponding property of the specified object (involving violent reflection)

When we find the attribute name, we need to find the attribute value of a student object corresponding to the attribute name, and use the obtained attribute name to call the get (object name) method. For example, to obtain the name,

        /**
         * Get property value
         */
        Object o = name.get(s);
        System.out.println(o);

       //For private, use violent reflection,
        age1.setAccessible(true);//Ignore access modifier
        Object o1 = age1.get(s);
        System.out.println(o1);

Console output:

For private, add a line of code after obtaining it with declared

Attribute name.setAccessible(true);

In this way, the access modifier can be ignored, which is called violent reflection, or burst for short.
There is a question here. Isn't it a private property that can be obtained with declared? Note that what you just obtained is the property name. Now you are looking for the property value, and the private property value should be reflected violently. For example, weight is an attribute name, but we can't directly ask your girlfriend how many kilograms you weigh. The specific weight (attribute value) of others is private.

You can try to output the attribute values obtained by several other methods.

Get construction method

Get constructor is used to create objects

1. Obtain the constructor first

| 4 kinds, codes as follows

  */
 		 //Gets the constructor of the specified public modifier. The parameters can be written in this way. If there are no parameters, they will not be written
        Constructor constructor1 = sclass1.getConstructor(String.class, int.class, String.class, int.class);
        //Gets the specified declared constructor (which can be private)
        Constructor declaredConstructor = sclass1.getDeclaredConstructor(String.class);

Similarly, with s is to get all and return the array. You can try it

Create object (violent reflection)

After obtaining the construction method, you need to create an object. Use newInstance(); Method, the parameter list writes the parameters I want to pass in. The second one I use is private, so violent reflection is used

declaredConstructor.setAccessible(true);
        Object zzy = declaredConstructor.newInstance("zzy");
        System.out.println(zzy);

Console output: because only the name is passed, the others are empty

You can try several other methods and output them

Get method (this is special)

The purpose of obtaining the method is to execute the method

Acquisition method

| 4 kinds, codes as follows

  * Acquisition method
         * 1 Gets the of the specified name public method
         * 2 Get all public Methods (including inherited)
         *
         * 3 Gets the declared method of the class with the specified name (inheritance does not count, implementation of the interface does not count)
         * 4 Get all declared methods
         */
        Method study = sclass1.getMethod("study");
        Method[] methods = sclass1.getMethods();

        Method sleep = sclass1.getDeclaredMethod("sleep");
        Method[] declaredMethods = sclass1.getDeclaredMethods();

After you get it and output it, you will find that the two without declared output a lot. This is because all classes inherit the Object class, and the inherited methods are also available by default, but we can't see them.
But not with declared, because declared means declared. The methods in the Object class inherited by the student class are not declared in this class, so they are not. However, the methods in the implementation interface are declared and will exist.

It is not difficult to see from here what the declaration of declared means. It is written and visible. No matter what modifier you write, you can get it. If you don't write it, you won't get it

Execution method

Call the invokes () method with the obtained method object

  Method study = sclass1.getMethod("study");
        Method[] methods = sclass1.getMethods();

        Method sleep = sclass1.getDeclaredMethod("sleep");
        Method[] declaredMethods = sclass1.getDeclaredMethods();
        sleep.setAccessible(true);
        sleep.invoke(s);

Console output:

Well, the specific acquisition methods are finished. Then, what's the use of this thing? It's more troublesome than we usually do!
Let's take a case to write a reflection so that it can create an object of any class and call any method without changing the code! So I understand

Reflection case (explain why reflection is the soul of the frame)

create profile

Create a pro.properties file under src, and write the following contents in the file (the second figure), the full path package name and the method name you want to call

Get profile

Load profile

Gets the value of the configuration file

reflex

The above four parts are uniformly written in the code

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        /**
         * Get the configuration file and use the class loader of the reflection class
         */
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        /**
         * Load the configuration file and call the load method with the properties object
         */
        Properties p = new Properties();
        p.load(is);
        
        /**
         * Get the value of the configuration file,
         */
        String classname = p.getProperty("classname");
        String methodname = p.getProperty("methodname");

        /**
         * Reflection, 4 steps
		        1 Get Class file
		        2 Get constructor creation object
		        3 Acquisition method
		        4 Execution method
         */
        Class<?> aClass = Class.forName(classname);

        Constructor<?> constructor = aClass.getConstructor();
        Object o = constructor.newInstance();

        Method method = aClass.getMethod(methodname);

        method.invoke(o);
    }
}

In this way, add other methods that I want to call the student class. Just modify them in the configuration file (pro.properties), and there is no need to change the code.
Even if I create a new teacher class, want to create a teacher class object and call the methods in the teacher class, I only need to modify the classname and methodname in the configuration file.

The above only represents personal views. If it is helpful, please give me a like. If there is any error, please correct it.

Keywords: Java

Added by jamesl73 on Mon, 06 Sep 2021 02:10:40 +0300