[Consolidate Java Foundation 06] This is probably the most detailed article on Java reflection

This article has been included in my GitHub: Java Development Book, welcome to give a Star: https://github.com/eson15/javaAll
I will continue to update, welcome star!
WeChat search: Wu Ge talks about programming , reply " notes ", you can receive a copy of Springboot classic study notes written by me with 100,000 words



Reflection is the soul element of frame design!

1. What is reflection?

The so-called reflection is a kind of self-observation ability possessed by the java language at runtime. Reflection enables your program code to get the internal information of the classes loaded into the JVM, allowing you to get the internal information of the required classes when the program is executed. It is not necessary to know the internal information of the required class when writing code; this method of dynamically obtaining information and dynamically calling objects can also be called Java's reflection mechanism.

Through Java's reflection mechanism, programmers can more deeply control the running process of the program, such as verifying the information input by the user while the program is running, and can also reverse the execution process of the program, which also makes reflection a flexible application The main tool.

2. The principle of reflection

2.1 Common classes and functions of reflection

The realization of the Java reflection mechanism requires the help of 4 classes:

  • Class object
  • Constructor object of the Constructor class
  • Property object of the Field class
  • Method object of the Method class

2.2 Methods included in the Class class

Through these four objects, we can roughly see the various components of a class. The core of which is the Class class, which is the basis for implementing reflection. The methods included in the Class class include:

Serial number name Features
1 getName() Get the fully qualified name of this type
2 getSuperClass() Get the fully qualified name of the direct superclass of this type
3 isInterface() Determine whether this type is a class type or an interface type
4 getTypeParamters() Get access modifier of this type
5 getInterfaces () Get an ordered list of the fully qualified names of any direct superinterface
6 getFields() Get field information
7 getMethods() Get method information

2.3 The main method of reflection

When applying reflection, we generally care about the constructor, attributes and methods of a class. Below we mainly introduce the methods for these three elements in the Class class:

2.3.1 The method to get the constructor

grammar Features
Constructor getConstructor(Class[] params) Obtain a public constructor that uses a special parameter type
Constructor[] getConstructors() Get all public constructors of the class
Constructor getDeclaredConstructor(Class[] params) Get a constructor that uses a specific parameter type (regardless of the access level)
Builder [] getDeclaredConstructors () Get all the constructors of the class (regardless of the access level)

2.3.2 Methods of obtaining field information

grammar Features
Field getField(String name) Get named public fields
Field[] getFields() Get all public fields of the class
Field getDeclaredField(String name) Get the named field of the class declaration
Field[] getDeclaredFields() Get all the fields declared by the class

2.3.3 Methods of obtaining method information

grammar Features
Method getMethod(String name, Class[] params) Use specific parameter types to obtain named public methods
Method[] getMethods() Get all public methods of the class
Method getDeclaredMethod(String name, Class[] params) Use the close-up parameter type to obtain the named method of the class declaration
Method[] getDeclaredMethods() Get all methods of class declaration

2.4 The basic steps of reflection actual combat

Class actionClass=Class.forName(“MyClass”);
Object action=actionClass.newInstance();
Method method = actionClass.getMethod(“myMethod”,null);
method.invoke(action,null);

The above is the most common example of reflection usage. The first two lines implement the loading, linking and initialization of the class (the newInstance method actually uses reflection to call the <init>method), and the second two lines implement the method object obtained from the class object and then executed Reflective call. Let's briefly analyze the specific principle of the code.

2.4.1 Get the Class object of the class

There are usually three different methods:
1) Class c = Class.forName("java.lang.String")
2) Class c = MyClass.class
3) For basic data types, you can use Class c = int.class or Class c = Statements like Integer.TYPE.

举个小栗子:先通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例

PS:反射的原理之一其实就是动态的生成类似于上述的字节码,加载到jvm中运行。

Imagine that in the above code, if you want to implement method.invoke(action,null)the myMethodmethod of calling the action object , you only need to implement such a Method class:

    Class Method{
    
    

        public Object invoke(Object obj,Object[] param){
    
    
    
            MyClass myClass=(MyClass)obj;
    
            return myClass.myMethod();
    
        }
    
    }

2.4.2 Get Method Object

首先来看一下Method对象是如何生成的:
- 使用Method m =myclass.getMethod("myMethod")获得了一个Class对象
- 接着对其进行判断,如果没有对应的cache,那么JVM就会为其创建一个并放入缓冲空间
- 处理器再判断Cache中是否存在"myMethod"
- 如果没有则返回NoSuchMethodException
- 如果存在那么就Copy一份"myMethod"对象并返回

The above Class object is constructed by the JVM when the class is loaded. The JVM manages a unique Class object for each class. This Class object maintains all the Method, Field, and Constructor caches of the class. This cache can also be used. It is called the root object. Every time the Method object obtained by getMethod holds a reference to the root object, because of some heavyweight Method member variables (mainly MethodAccessor), we don’t want to reinitialize every time a Method object is created, so all represent the same The Method object of the method all share the MethodAccessor of the root object, and every time it is created, the copy method of the root object is called to make a copy:

Method copy() {
    
     
    Method res = new Method(clazz, name, parameterTypes, returnType,

                            exceptionTypes, modifiers, slot, signature,

                            annotations, parameterAnnotations, annotationDefault);
    res.root = this;
    res.methodAccessor = methodAccessor;
    return res;
}

2.4.3 Invoke the invoke() method

After obtaining the Method object, the process of calling the invoke method is as follows:

m.invoke(obj,param);

- 首先调用MethodAccess.invoke
- 如果该方法的累计调用次数<=15,会创建出NativeMethodAccessorImp
- 如果该方法的累计调用次数>15,会由java代码创建出字节码组装而成的MethodAccessorImpl

We can see that after calling Method.invoke, it will be directly adjusted MethodAccessor.invoke. MethodAccessor is an instance shared by all the methods with the same name mentioned above, created by ReflectionFactory. The creation mechanism uses a method called inflation (after JDK1.4): If the cumulative number of calls of this method is <=15, NativeMethodAccessorImpl will be created, and its implementation is to directly call the native method to achieve reflection; if the cumulative number of calls of this method If the number of calls is greater than 15, a MethodAccessorImpl assembled by bytecode will be created by java code. (Whether to use inflation and 15 can be adjusted in the jvm parameter)

Taking the call MyClass.myMethod(String s)as an example, the generated MethodAccessorImpl bytecode translated into Java code is roughly as follows:

public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    
        
    public Object invoke(Object obj, Object[] args)  throws Exception {
    
    
        try {
    
    
            MyClass target = (MyClass) obj;
            String arg0 = (String) args[0];
            target.myMethod(arg0);
        } catch (Throwable t) {
    
    
            throw new InvocationTargetException(t);
        }
    }
}

Through a detailed analysis of the running process of java, we can find that the first and 16th calls are the most time-consuming (initialization of NativeMethodAccessorImpl and bytecode assembly MethodAccessorImpl). Initialization is inevitable, so the initialization of the native method will be faster, so the first few calls will use the native method.

As the number of calls increases, each reflection using JNI to cross the native boundary will hinder optimization. Relatively speaking, using assembled bytecodes can directly implement reflection in the form of Java calls, playing the role of JIT optimization. It avoids the performance loss of encapsulation/decapsulation of JNI in order to maintain OopMap (the data structure used by HotSpot to realize accurate GC).

In the case that MethodAccessor has been created, the implementation using the Java version will be faster than the native version. So when the number of calls reaches a certain number (15 times), it will switch to the Java implementation version to optimize possible more frequent reflection calls in the future.

3. Java reflection application (Hibernate framework)

As we already know, the Java reflection mechanism provides a versatile method of dynamically linking program components, which allows the program to create and control objects of any class (according to security restrictions) without having to hard-code the target class in advance. These characteristics make reflection particularly suitable for creating libraries that collaborate with objects in a very common way. For example, reflection is often used in frameworks where the persistent storage objects are databases, XML, or other external formats. Let's take the Hibernate framework as an example to explain the importance of reflection.

Hibernate is a java framework that shields JDBC and implements ORM. Using this framework, we can abandon tedious SQL statements and use the save() method of the Session class in Hibernate to directly store objects of a certain class in the database. It is the code Hibernate that involves the sql statement to do it for us. At this time, a question arises. How does Hibernate know what attributes the object that he wants to store has? What are these attributes? Think about it, how to construct the SQL statement when it stores the object properties in the database? OK, the role of reflection is now reflected!

Let’s take an example to illustrate. For example, we define a User class. This User class has 20 attributes and the get and set methods of these attributes. Correspondingly, there is a User table in the database, and this User table corresponds to 20 fields. Suppose we extract a record from the User table, and now we need to assign the contents of the 20 fields of this record to the 20 attributes of a User object myUser, and the Hibernate framework does not know this User class when it is compiled. The myUser.getXXX or myUser.setXXX methods cannot be called directly. At this time, reflection is used. The specific processing process is as follows:

  1. Construct a PreparedStament statement according to the query conditions, which returns the values ​​of 20 fields;

  2. Hibernate obtains the property list list (a String array) of the User class and the types of these properties by reading the configuration file;

  3. Create the Class object c of the class myUser belongs to; c = myUser.getClass();

  4. Construct a for loop, the number of loops is the length of the list;

    • Read the value of list[i], and then construct the set method corresponding to the attribute;

    • Determine the type XXX of list[i], call getXXX(i) in the PreparedStament statement, and then get the value of the i field;

    • Use the value obtained in 4.2 as the parameter of the set method obtained in 4.1, which completes the assignment of a field like an attribute, and loops until the end of the program;

Without reflection, it is hard to imagine how difficult it would be to implement such a complex function!

Having said that, while reflection brings us convenience, it also has its own shortcomings, such as low performance, low security, more complicated process, etc. Interested readers can also study in depth in actual work!

Author info

[Author]: Wu Ge
[public account]: Wu Ge talks about programming . Welcome everyone to pay attention~
【Profile of the author】: Master of Tongji University. Successively mining pits in Huawei, HKUST Xunfei, and Pinduoduo. A self-taught Java rookie, looking forward to your attention.

Like is my biggest encouragement
↓↓↓↓↓↓

Guess you like

Origin blog.csdn.net/eson_15/article/details/110749618