Introduction to Java reflection, simple and practical [one piece is enough]

摘自==》http://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html

There is a word "anti" in reflection, so if you want to explain reflection, you must start with "positive".

Under normal circumstances, when we use a class, we must know what class it is and what it is used for. So we directly instantiate this class, and then use this class object to operate.

Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);

The above initialization of class objects can be understood as "positive".

The reflection is that I don't know what the class object I want to initialize at the beginning, and naturally I can't use the new keyword to create an object.

At this time, we use the reflection API provided by the JDK to make reflection calls:

Class clz = Class.forName("com.chenshuyi.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);

The execution results of the above two pieces of code are actually exactly the same. But the idea is completely different. The first piece of code has already determined the class to run (Apple) when it is not running, while the second piece of code uses the string value to know the class to run (com .chenshuyi.reflect.Apple).

So what is reflection?

Reflection is to know what the class to be operated on at runtime, and to obtain the complete structure of the class at runtime and call the corresponding method.

A simple example

The complete program code of the sample program mentioned above is as follows:

public class Apple {

    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public static void main(String[] args) throws Exception{
        //正常的调用
        Apple apple = new Apple();
        apple.setPrice(5);
        System.out.println("Apple Price:" + apple.getPrice());
        //使用反射调用
        Class clz = Class.forName("com.chenshuyi.api.Apple");
        Method setPriceMethod = clz.getMethod("setPrice", int.class);
        Constructor appleConstructor = clz.getConstructor();
        Object appleObj = appleConstructor.newInstance();
        setPriceMethod.invoke(appleObj, 14);
        Method getPriceMethod = clz.getMethod("getPrice");
        System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
    }
}

You can see from the code that we used reflection to call the setPrice method and passed a value of 14. Then use reflection to call the getPrice method to output its price. The entire output of the above code is:

Apple Price:5
Apple Price:14

As can be seen from this simple example, in general we use reflection to obtain an object:

  • Get the Class object instance of the class
Class clz = Class.forName("com.zhenai.api.Apple");
  • Obtain the Constructor object according to the Class object instance
Constructor appleConstructor = clz.getConstructor();
  • Use the newInstance method of the Constructor object to obtain a reflection class object
Object appleObj = appleConstructor.newInstance();

If you want to call a method, you need to go through the following steps:

  • Get the Method object of the method
Method setPriceMethod = clz.getMethod("setPrice", int.class);
  • Invoke method using invoke method
setPriceMethod.invoke(appleObj, 14);

At this point, we have been able to grasp the basic use of reflection. But if you want to learn more about reflection, you need to have a deeper understanding of the common APIs of reflection.

In JDK, reflection-related APIs can be divided into the following aspects: obtaining reflected Class objects, creating class objects through reflection, and obtaining class attribute methods and constructors through reflection.

Reflection common API

Get the Class object in reflection

In reflection, to get a class or call a method of a class, we first need to get the Class object of the class.

In the Java API, there are three ways to obtain Class objects:

The first is to use the Class.forName static method. When you know the full path name of the class, you can use this method to get the Class class object.

Class clz = Class.forName("java.lang.String");

The second is to use the .class method.

This method is only suitable for classes that know the operation before compilation.

Class clz = String.class;

The third is to use the getClass() method of the class object.

String str = new String("Hello");
Class clz = str.getClass();

Create class objects through reflection

There are two main ways to create a class object through reflection: through the newInstance() method of the Class object, and through the newInstance() method of the Constructor object.

The first: through the newInstance() method of the Class object.

Class clz = Apple.class;
Apple apple = (Apple)clz.newInstance();

The second: through the newInstance() method of the Constructor object

Class clz = Apple.class;
Constructor constructor = clz.getConstructor();
Apple apple = (Apple)constructor.newInstance();

You can choose a specific construction method to create a class object through the Constructor object, while you can only use the default parameterless construction method through the Class object. The following code calls a parameterized constructor to initialize the class object.

Class clz = Apple.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("红富士", 15);

Obtain class attributes, methods, and constructors through reflection

We can get the properties of the Class class through the getFields() method of the Class object, but we cannot get the private properties.

Class clz = Apple.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

The output is:

price

And if you use the getDeclaredFields() method of the Class object, you can get all properties including private properties:

Class clz = Apple.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

The output is:

name
price

As with obtaining class attributes, when we go to obtain class methods and class constructors, if we want to obtain private methods or private constructors, we must use methods with the declared keyword.

Reflection source code analysis

After we understand how to use reflection, today we will take a look at how reflection is implemented in the JDK source code. Maybe you have never used reflection before, but you will encounter the following exceptions when developing Web projects:

java.lang.NullPointerException 
...
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:497)

You can see that the exception stack points out that the exception is in the 497th invoke method of Method. In fact, the invoke method referred to here is the invoke method in our reflection call method.

Method method = clz.getMethod("setPrice", int.class); 
method.invoke(object, 4);   //就是这里的invoke方法

For example, in the Spring configuration we often use, there are often related bean configurations:

<bean class="com.chenshuyi.Apple">
</bean>

After we configure the above configuration in the XML file, Spring will use reflection to load the corresponding Apple class at startup. When the Apple class does not exist or a heuristic exception occurs, the exception stack will point the exception to the invoke method called.

It can be seen from this that we usually use reflection in many frameworks, and the most final thing in reflection is the invoke method of the Method class.

Guess you like

Origin blog.csdn.net/sjmz30071360/article/details/88368135