Java reflection-the soul of the framework (quite important)

Preface

Continuing from the previous article, I just finished learning reflection recently, and there are still some things that are not understandable, so I write a blog to list the content I just learned. The content of this article is all my own notes and my own understanding. I would like to ask the big guys for the place.

The concept of reflection

What is reflection (Reflection): Encapsulate the various components of the class as other objects, this is the reflection mechanism. Reflection as the soul of the framework is used more in various frameworks.

The benefits of reflection

These objects can be manipulated during the running of the program, which can be decoupled to improve the scalability of the program. For example, reflection is generally used when loading database configuration files.

Dynamic language understanding

Java itself is a static language, but reflection can make Java very flexible.
The so-called dynamic language I personally understand is a language that can load objects during the running of the program.

About Class

Three ways to obtain Class objects

 public static void main(String[] args ) throws Exception{
    
    
        //创建Class对象的三种方式
        //1、通过Class.forName("全类名")
        Class c1 = Class.forName("cn.sjy.Person");
        System.out.println(c1);
        //2、通过 类名.class
        Class<Person> c2 = Person.class;
        System.out.println(c2);
        //3、 通过对象.getClass()
        Person person = new Person();
        System.out.println(person.getClass());
    }

The result is shown in the figure:
Insert picture description here
It can be seen that all three methods obtain a Class object. It is worth mentioning that the same bytecode file (.class file) is only loaded once during a program run. All types can have Class objects, like properties, methods, constructors, generics, annotations, etc.

Understanding of Class

The Class class contains all the information of the class, including construction methods, properties, methods, etc. Reflection can also be understood as a process in which a Class object is returned after the Class class is loaded into memory, and its own method attributes are mapped out through this Class object.

Class loading and the understanding of ClassLoader

Loading process

The class name .class is a bytecode file. We need to know that a Java program runs from a .java file to a .class file, and then loads the .class file into memory, that is, puts the .class file into the JVM Only when the .class file is put into the JVM can it be cross-platform. The role of the ClassLoader is to put the .class file into the JVM and load it into a Class object (java.lang.Class object), and only the Class object can call other methods.

ClassLoader (ClassLoader)

The class loader is responsible for reading the .class file and converting it into an instance of the java.lang.Class class. Each such instance is used to represent a java class. The newInstance() method of this instance can create the class An object. Through reflection, the class is completely transparent to us. Regardless of whether you are private or what, we can get anything we want through reflection. Generally speaking, when a property is private, we need to call the get and set methods. Value and assignment, but you can directly assign and value private modified attributes through reflection. Of course, this also has drawbacks, that is slow! Compared to new an object to call properties and methods, reflection is much slower!
Summarize the class loader in one sentence (personal understanding): After obtaining a Class instance corresponding to a class, you can obtain all the information of the class.
The method of obtaining class information through the Class instance is called reflection (Reflection)

Class object function and its instance

Dynamically call objects through reflection

The code is the same as the previous blog, here is a summary

 public static void main(String[] args ) throws Exception{
    
    
        //获取Class对象
        Class c1 = Class.forName("cn.sjy.Person");
        //实例化该对象,创建由此类对象表示的新的对象
        Person person = (Person) c1.newInstance();
        //newInstance()方法规定调用无参的构造函数
        System.out.println(person);

        //获得一个类的构造器
        Person person2 = (Person)c1.getConstructor(int.class, String.class).newInstance(2017021, "虎哥");
        //将这个类的构造器进行实例化
        System.out.println(person2);

        //调用一个普通方法
        Method fan = c1.getDeclaredMethod("fan");
        //需要忽略访问权限修饰符的安全检查--》暴力反射
        fan.setAccessible(true);
        fan.invoke(person);

        //操作属性
        Field id = c1.getDeclaredField("id");
        id.setAccessible(true);
        id.set(person,123);
        System.out.println(id.get(person));
    }
 public static void main(String[] args ) throws Exception {
    
    
        //获取Class对象,将这个字节码文件加载进内存
        Class c1 = Class.forName("cn.sjy.Person");
        //实例化这个Class对象,创建一个由此Class对象表示的新对象
            //newInstance()方法只能调用无参的构造函数
        Person person = (Person)c1.newInstance();

        //输出一个无参的构造函数
        System.out.println(person);
        //调用一个有参的构造函数,并且将其实例化
        Person p = (Person) c1.getConstructor(int.class, String.class).newInstance(2017021, "反射君");
        System.out.println(p);

        //调用属性,如果是public调用getField即可,但是如果是private需要调用getFDeclaredFeild方法
        Field id = c1.getDeclaredField("id");
        //关闭安全检查
        id.setAccessible(true);
        id.set(p,2017021);
        id.set(person,2017022);
        //输出这个属性的值
        System.out.println(id.get(person));
        System.out.println(id.get(p));

        //调用普通方法
        Method fan = c1.getDeclaredMethod("fan");
        fan.setAccessible(true);
        fan.invoke(p);
    }

Results of the second piece of code:
Insert picture description here

Person class

package cn.sjy;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    
    
    public int id;
    private String name;

    /**普通方法*/
    private void fan(){
    
    
        System.out.println("通过反射来调用普通方法!");
    }
}

My Person class uses a plug-in, through annotations you can get the construction method and the like.

Reflection case in detail

Call a common method by obtaining information about a configuration file

public static void main(String[] args ) throws Exception{
    
    
        //获取配置文件的位置
        File file = new File("D:\\JavaIDEA\\Test\\src\\pro.properties");
        //调用Properties类-->唯一一个和IO流结合的集合
            //Properties类实现了Map接口
        Properties pro = new Properties();
        //调用一个FileInputStream类读取一个文件
        FileInputStream fis = new FileInputStream(file);
        //读取这个文件的信息
        pro.load(fis);
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
        //输出文件的信息
        System.out.println(className);
        System.out.println(methodName);

        //根据配置文件的值创建Class对象
        Class c1 = Class.forName(className);

        //调用Person的普通方法
        Method fan = c1.getDeclaredMethod("fan");
        //因为该普通方法是private修饰的所以需要关闭检测
        fan.setAccessible(true);
        //执行该方法
        fan.invoke(c1.newInstance());
    }

The result is shown in the figure (this Person class and the above are a class):
Insert picture description here
Next, let’s talk about the role of each step in detail.
Class.forName ("full class name"): Load this class into memory by the full class name and then instantiate it To generate a Class object.
.newInstance(): instantiate this Class object, another way is to call the parameterless constructor of this object, pay attention to the parameterless constructor, newInstance() calls the parameterless constructor by default, if you want to call The parameterized constructor needs to be implemented using getConstractor(Object.class,Object.class...).newInstance(obj.obj...).
Note: The static{} code block is run before the initialization of the class, so the static{} code block is generally used to load configuration files and other information.
Active reference of the class (the initialization of the class will definitely occur), reflection, new an object
Passive reference of the class (the initialization of the class will not occur), subclass, parent class variable, array

to sum up

I have learned some knowledge about Java reflection at present. I have learned it very shallowly, but I have not done it in depth. I plan to go deeper when I come into contact with the framework in the future. Next, I will sort out the content about multithreading. The ability is limited, so bear with me. Just sauce~

Guess you like

Origin blog.csdn.net/weixin_44475741/article/details/109450921