Sort out the understanding of java reflection mechanism

Insert picture description here
First of all, let's understand the JVM, what is the JVM, the Java virtual machine, the reason why java can cross-platform is because of this thing, you can understand it as a process, program, but his role is to run your code. The picture above is the java memory model. Our focus is on a method area, a stack, and a heap. When the teacher does not go deeper when I first learn, I will only tell you that java memory is divided into heap and stack. It is easy to understand!

If you wrote a piece of code: Object o = new Object ();

It's running!

First, the JVM will start, your code will be compiled into a .class file, and then loaded into the memory of the jvm by the class loader, your class Object will be loaded into the method area, and the class object of the Object class will be created on the heap. This is not a new object, but a class type object. Each class has only one class object, which serves as an interface to the data structure of the method area class. Before creating an object, jvm will first check whether the class is loaded, look for the class object corresponding to the class, if it is loaded, then allocate memory for your object, and the initialization is the code: new Object ().

The above process is that you write the code you wrote to the jvm to run. After running, it will be over, the jvm is closed, and your program will stop.

Why talk about this? Because to understand reflection, you must know what scene it is used in.

The subject thinks that the above program object is new, and the program is equivalent to writing to the jvm to run. If a request is suddenly encountered on a server, a class is needed, oops, but it is not loaded into the jvm, do you want to stop and write your own code, new, oh, start the server, (brain)!

What is reflection? When our program is running, we need to dynamically load some classes. These classes may not be used before, so they do n’t need to be loaded into the jvm, but are loaded as needed at runtime. Such benefits are self-evident for the server. An example of the bottom of our project is sometimes using mysql, sometimes using oracle, need to dynamically load the driver class according to the actual situation, this time reflection is useful, assuming com.java.dbtest.myqlConnection, com.java.dbtest.oracleConnection We need to use this class. At this time, our program is written more dynamically, through Class tc = Class.forName ("com.java.dbtest.TestConnection"); Through the full class name of the class, jvm is found in the server and Load this class, and if it is oracle, the incoming parameters become another. At this time you can see the benefits of reflection, this dynamic reflects the characteristics of java! To cite multiple examples, if you have contacted with spring, you will find that when you configure a variety of beans, they are configured in the form of a configuration file. You need to configure which beans you need to use, and the spring container will be based on your Need to dynamically load, your program can run robustly.

What is reflection?
Reflection (Reflection) is one of the characteristics of Java, which allows running Java programs to obtain their own information, and can manipulate the internal properties of the class or object.

Oracle's official interpretation of reflection is:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

The core of reflection is that the JVM dynamically loads classes or calls methods / access properties at runtime. It does not need to know in advance (when writing code or compilation time) who the running object is.

Java reflection mainly provides the following functions:

Judge the class to which any object belongs
at runtime; construct the object of any class
at runtime; judge the member variables and methods of any class at runtime (even private methods can be called through reflection);
call any at runtime The focus of an object's method
: run time rather than compile time

Second, the main purpose of reflection
Many people think that reflection is not widely used in actual Java development applications, but it is not. When we are using an IDE (such as Eclipse, IDEA), when we enter an object or class and want to call its properties or methods, the compiler will automatically list its properties or methods when you press the dot. Will use reflection.

The most important use of reflection is to develop various general frameworks. Many frameworks (such as Spring) are configurable (such as configuring beans through XML files). In order to ensure the universality of the framework, they may need to load different objects or classes and call different methods according to the configuration file. To reflection, the objects that need to be loaded are dynamically loaded at runtime.

To give an example, in the development using Struts 2 framework, we generally configure Action in struts.xml, such as:

<action name="login"
class="org.ScZyhSoft.test.action.SimpleLoginAction"
method="execute">
<result>/shop/shop-index.jsp</result>
<result name="error">login.jsp</result>
</action>

The configuration file establishes a mapping relationship with Action. When the View layer sends a request, the request will be intercepted by StrutsPrepareAndExecuteFilter, and then StrutsPrepareAndExecuteFilter will dynamically create an Action instance. For example, if we request login.action, StrutsPrepareAndExecuteFilter will parse the struts.xml file, retrieve the Action whose name is login in the action, and create a SimpleLoginAction instance based on the class attribute, and use the invoke method to call the execute method. This process is inseparable from reflection.

For developers working with frameworks, reflection is small but very useful. It is the core of various container implementations. For the average developer, if you don't go deep into the framework development, you will use a little less reflection, but it is also very useful to understand the underlying mechanism of the framework to help enrich your programming ideas.

Third, the basic application
of reflection We mentioned above that reflection can be used to determine the class to which any object belongs, obtain a Class object, construct any object and call an object. Here we introduce the use and implementation of basic reflection functions (reflection-related classes are generally in the java.lang.relfect package).

1.
There are three ways to get Class objects :

(1) Use the forName static method of Class class:

public static Class<?> forName(String className)

For example, in JDBC development, this method is often used to load the database driver:

Class.forName(driver);

(2) Get the class of an object directly, for example:

	
Class<?> klass = int.class;
Class<?> classInt = Integer.TYPE;

(3) Call the getClass () method of an object, such as:

	
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();

2. Judge whether it is an instance of a class In
general, we use the instanceof keyword to judge whether it is an instance of a class. At the same time, we can also use the isInstance () method of the Class object in reflection to determine whether it is an instance of a class. It is a native method:

public native boolean isInstance(Object obj);

3. Create instances
There are two main ways to generate objects through reflection.

Use the newInstance () method of the Class object to create an instance of the class corresponding to the Class object.

Class<?> c = String.class;
Object str = c.newInstance();

First obtain the specified Constructor object through the Class object, and then call the newInstance () method of the Constructor object to create an instance. This method can use the specified constructor to construct an instance of the class.

/获取String所对应的Class对象
Class<?> c = String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("23333");
System.out.println(obj);

4. Obtaining methods
Obtaining the collection of methods of a Class object mainly includes the following methods:

The getDeclaredMethods method returns all methods declared by the class or interface, including public, protected, default (package) access, and private methods, but not inherited methods.

public Method[] getDeclaredMethods() throws SecurityException

The getMethods method returns all public methods of a class, including the public methods of its inherited classes.

public Method[] getMethods() throws SecurityException

The getMethod method returns a specific method, where the first parameter is the method name, and the following parameters are the objects of the method corresponding to the Class object.

public Method getMethod(String name, Class<?>... parameterTypes)

It may be difficult to understand what is described in this way. We use examples to understand these three methods:

package org.ScZyhSoft.common;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class test1 {
public static void test() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> c = methodClass.class;
Object object = c.newInstance();
Method[] methods = c.getMethods();
Method[] declaredMethods = c.getDeclaredMethods();
//获取methodClass类的add方法
Method method = c.getMethod("add", int.class, int.class);
//getMethods()方法获取的所有方法
System.out.println("getMethods获取的方法:");
for(Method m:methods)
System.out.println(m);
//getDeclaredMethods()方法获取的所有方法
System.out.println("getDeclaredMethods获取的方法:");
for(Method m:declaredMethods)
System.out.println(m);
}
}
class methodClass {
 
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}

The results of the program run are as follows:

getMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
getDeclaredMethods获取的方法:
public int org.ScZyhSoft.common.methodClass.add(int,int)
public int org.ScZyhSoft.common.methodClass.sub(int,int)

It can be seen that the methods obtained through getMethods () can obtain the methods of the parent class, such as the methods defined under java.lang.Object.
5. Obtaining constructor information
The usage of the obtaining class constructor is similar to the usage of the above obtaining method. Mainly through the Class class getConstructor method to get an instance of the Constructor class, and the Constructor class has a newInstance method can create an object instance:

public T newInstance(Object ... initargs)

This method can call the corresponding Constructor to create an object instance based on the passed parameters.

6. Obtain the information of the member variables (fields) of the class.
These are mainly these methods, which will not be repeated here:

getFiled: access public member variables
getDeclaredField: all declared member variables, but cannot get the member variables of its parent class
getFileds and getDeclaredFields The method is the same as above (refer to Method)

7. Calling a method
When we get a method from the class, we can use the invoke () method to call this method. The prototype of the invoke method is:

public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException

Here is an example:

public class test1 {
 
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> klass = methodClass.class;
//创建methodClass的实例
Object obj = klass.newInstance();
//获取methodClass类的add方法
Method method = klass.getMethod("add",int.class,int.class);
//调用method对应的方法 => add(1,4)
Object result = method.invoke(obj,1,4);
System.out.println(result);
}
 
}
 
class methodClass {
 
public final int fuck = 3;
public int add(int a,int b) {
return a+b;
}
public int sub(int a,int b) {
return a+b;
}
}

For a detailed explanation of the invoke method, I will write an article later to analyze the invoke process in depth.
8. Using reflection to create arrays
Arrays are a special type in Java, which can be assigned to an Object Reference. Let's take a look at an example of using reflection to create an array:

public static void testArray() throws ClassNotFoundException {
Class<?> cls = Class.forName("java.lang.String");
Object array = Array.newInstance(cls,25);
//往数组里添加内容
Array.set(array,0,"hello");
Array.set(array,1,"Java");
Array.set(array,2,"fuck");
Array.set(array,3,"Scala");
Array.set(array,4,"Clojure");
//获取某一项的内容
System.out.println(Array.get(array,3));
}

The Array class is java.lang.reflect.Array class. We create an array object through Array.newInstance (), its prototype is:

public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}

The newArray method is a native method, and its specific implementation in the HotSpot JVM will be studied later. Here, the source code is first posted:

private static native Object newArray(Class<?> componentType, int length)
throws NegativeArraySizeException;

Source directory: openjdk \ hotspot \ src \ share \ vm \ runtime \ reflection.cpp

arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
if (element_mirror == NULL) {
THROW_0(vmSymbols::java_lang_NullPointerException());
}
if (length < 0) {
THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
}
if (java_lang_Class::is_primitive(element_mirror)) {
Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL);
return TypeArrayKlass::cast(tak)->allocate(length, THREAD);
} else {
Klass* k = java_lang_Class::as_Klass(element_mirror);
if (k->oop_is_array() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
}
return oopFactory::new_objArray(k, length, THREAD);
}
}

In addition, the set and get methods of the Array class are both native methods, corresponding to the Reflection :: array_set and Reflection :: array_get methods in the HotSpot JVM, which will not be analyzed in detail here.

** Four considerations
for reflection ** Since reflection will consume additional system resources, if you do not need to dynamically create an object, you do not need to use reflection.

In addition, the permission check can be ignored when the method is called by reflection, so it may break the encapsulation and cause security problems.

Published 17 original articles · Likes0 · Visits 224

Guess you like

Origin blog.csdn.net/weixin_42531204/article/details/105328505