Reflection--the soul of Java framework design

I. Overview

After learning the advanced frameworks at the JAVASE stage, such as Spring, Mybatis, etc., you will always think about how these frameworks work, and what are the underlying principles? But to understand the design principles of these high-level frameworks, first of all, the Java foundation must be solid. The reflection, annotation, dynamic proxy and design patterns in the basic stage of Java constitute the foundation of some high-level frameworks. In fact, in the study of the basics, I have repeatedly learned reflection, but I only used it when I was studying, and I did not use reflection in the subsequent learning, so I rewrite the relevant knowledge of reflection.

List<Integer> list = new ArrayList<>();

The above is the simplest new object, and the premise of this new is that I already know what the initialized object is, so this class is instantiated in the compilation phase, so think, if it is in the runtime phase, we need to go What about a new object, that is to say, we don’t know the specific type of this object in advance. For example, in the IOC in Spring, a specific annotation can be marked during operation or a fully qualified class name can be configured in the configuration file. For instantiation, it is obvious that using new is not possible, because the configuration file is changeable

At this time, we need to use the powerful reflection of our Java

Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为 Java 的反射机制。(Pay attention to keyword runtime)

A Java class has three parts: instance variables (data members), construction methods, and instance methods. The function of the reflection mechanism is to obtain and execute these three parts of a Java class at runtime, as follows:

  • inRuntimeDetermine the type of any object
  • inRuntimeConstruct an object of any class
  • inRuntimeDetermine the member variables and methods of any class
  • inRuntimeCall the method of any object, and even call the private method.

In terms of specific application, Java reflection is a set of APIs under java.lang.reflect

Class package effect
java.lang.Class Represents a class
java.lang.reflect.Constructor Representative class construction method
java.lang.reflect.Field Member variables representing the class
java.lang.reflect.Method Representative class method
java.lang.reflect.Edit Modifiers used to determine and obtain a certain class, variable or method

The methods of these classes are introduced below, and then a case is given at the end

Two, the method in the reflection API

2.1 Get a class

There are three ways to get a class:

  1. Use the .class method to get a class
  2. Use the getClass() method of the Object class
  3. Use Class.forName() method
//使用.class方法
Class<Person> personClass = Person.class;
//使用Object类的getClass()方法
Person person = new Person();
Class<? extends Person> personClass1 = person.getClass();
//使用Class.forName()方法
Class<?> personClass2 = Class.forName("cn.Reflect.Person");

2.2 Methods in Class

After obtaining the Class object, you can call the following methods to obtain other parts of the class

1. Get member variables

method description
Field[] getFields() Get all public modified member variables
Field getField(String name) Get the public modified member variable of the specified name
Field[] getDeclaredFields() Get all member variables, regardless of modifiers
Field getDeclaredField(String name) Get the member variable of the specified name

2. Get the construction method

These methods are similar to obtaining member variables, and do not describe too much

method description
Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)
Constructor getDeclaredConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()

3. Get member method

method description
Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes)

4. Get the full class name

  • String getName()

5. Get modifiers

  • int getModifiers()

6. Return a new instance

  • Object newInstance()

2.3 Methods in the Field class

method description
void set(Object obj, Object value) Settings
Object get(Object obj) Get value
setAccessible(true) This method should be called before obtaining the private modified value
AnnotatedType getAnnotatedType() Get the annotation of the attribute
String getName() Get field name
int getModifiers() Get field permissions

2.4 Methods in the Constructor class

method description
T newInstance(Object… initargs) Construct the object through the constructor
String getName() Get field name
int getModifiers() Get field permissions

2.5 Methods in the Method class

method description
Object invoke(Object obj, Object… args) Execution method
String getName() Get field name
int getModifiers() Get field permissions

Three, some cases

3.1 All information under the output category

From the Java core technology, enter a fully qualified class name, and output all the information of the class

package cn.Reflect;

import javafx.scene.input.InputMethodTextRun;

import java.lang.reflect.*;
import java.util.Scanner;

public class ReflectDemo2 {
    
    
    private StringBuffer sb;
    private String name;
    private Class clazz;
    public ReflectDemo2(){
    
    
        sb = new StringBuffer();
        //输入全限定类名
        Scanner sc = new Scanner(System.in);
        String name = sc.next();
        try {
    
    
            clazz = Class.forName(name);
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }
    public void printSuper(){
    
    
        //获取父类
        Class<?> superclass = clazz.getSuperclass();
        //  public class java.lang.Double extends java.lang.Number
        //getModifiers方法返回一个int类型来标识,通过Modifier类转为具体的类型如public等等
        String modifiers = Modifier.toString(clazz.getModifiers());
        if(modifiers.length() > 0){
    
    
            sb.append(modifiers + " ");
        }
        sb.append("class" + name);
        //判断是否有父类并且该父类不为Object
        if(superclass != null && superclass != Object.class){
    
    
            sb.append("extends" + superclass.getName());
        }
        sb.append("\n{\n");
    }
    public void printConstructors(){
    
    
        //获取所有构造方法
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
    
    
            sb.append("\t");
            //public java.lang.Double(java.lang.String);
            //获取权限修饰符
            String modifiers = Modifier.toString(c.getModifiers());
            sb.append(modifiers + " ");
            //获取构造器方法名称
            String name = c.getName();
            //获取参数
            Class[] parameters = c.getParameterTypes();
            sb.append(name + "(");
            for(int i = 0;i < parameters.length;i++){
    
    
                if(i > 0) sb.append(",");
                sb.append(parameters[i].getName());
            }
            sb.append(");\n");
        }
    }
    public void printMethod(){
    
    
        //public int compareTo(java.1ang.Object);
        //获取所有方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods) {
    
    
            sb.append("\t");
            //获取权限修饰符
            String modifiers = Modifier.toString(m.getModifiers());
            sb.append(modifiers + " ");
            //获取返回值
            Class<?> returnType = m.getReturnType();
            sb.append(returnType.getName() + " " + m.getName() + "(" );
            //获取方法参数
            Class<?>[] parameters = m.getParameterTypes();
            for(int i = 0;i < parameters.length;i++){
    
    
                if(i > 0) sb.append(",");
                sb.append(parameters[i].getName());
            }
            sb.append(");\n");
        }
        sb.append("}");
    }
    public void printField(){
    
    
        //public static final double POSITIVE_INFINITY;

        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
    
    
            sb.append("\t");
            //获取权限修饰符
            String modifiers = Modifier.toString(f.getModifiers());
            sb.append(modifiers + " ");
            //获取类型
            Class<?> type = f.getType();
            sb.append(type.getName() + " " + f.getName() + ";\n");
        }

    }
    public void printInfo(){
    
    
        this.printSuper();
        this.printField();
        this.printConstructors();
        this.printMethod();
        System.out.println(sb.toString());
    }
    public static void main(String[] args) {
    
    
        ReflectDemo2 reflectDemo2 = new ReflectDemo2();
        reflectDemo2.printInfo();
    }
}

This case is actually some combination of calls to the above API. When java.lang.Double is input, the console output:

public final classnullextendsjava.lang.Number
{
    
    
	public static final double POSITIVE_INFINITY;
	public static final double NEGATIVE_INFINITY;
	public static final double NaN;
	public static final double MAX_VALUE;
	public static final double MIN_NORMAL;
	public static final double MIN_VALUE;
	public static final int MAX_EXPONENT;
	public static final int MIN_EXPONENT;
	public static final int SIZE;
	public static final int BYTES;
	public static final java.lang.Class TYPE;
	private final double value;
	private static final long serialVersionUID;
	public java.lang.Double(double);
	public java.lang.Double(java.lang.String);
	public boolean equals(java.lang.Object);
	public static java.lang.String toString(double);
	public java.lang.String toString();
	public int hashCode();
	public static int hashCode(double);
	public static double min(double,double);
	public static double max(double,double);
	public static native long doubleToRawLongBits(double);
	public static long doubleToLongBits(double);
	public static native double longBitsToDouble(long);
	public volatile int compareTo(java.lang.Object);
	public int compareTo(java.lang.Double);
	public byte byteValue();
	public short shortValue();
	public int intValue();
	public long longValue();
	public float floatValue();
	public double doubleValue();
	public static java.lang.Double valueOf(java.lang.String);
	public static java.lang.Double valueOf(double);
	public static java.lang.String toHexString(double);
	public static int compare(double,double);
	public static boolean isNaN(double);
	public boolean isNaN();
	public static boolean isFinite(double);
	public static boolean isInfinite(double);
	public boolean isInfinite();
	public static double sum(double,double);
	public static double parseDouble(java.lang.String);
}

3.2 Create the object and execute the method based on the class name

Requirement: Configure the two properties of className and methodName in the properties configuration file, you need to create the corresponding object according to the configuration file and execute the methodName method

public class ReflectDemo3 {
    
    
    public static void main(String[] args) {
    
    
        //1.创建properties对象
        Properties properties = new Properties();
        //获取根路径下的properties流对象
        InputStream inputStream = ReflectDemo3.class.getClassLoader().getResourceAsStream("pro.properties");
        try {
    
    
            properties.load(inputStream);
            //获取对应属性
            String className = properties.getProperty("className");
            String methodName = properties.getProperty("methodName");
            //得到该类对象
            Class<?> clazz = Class.forName(className);
            //创建该对象的无参构造
            Object obj = clazz.newInstance();
            //获取方法对象
            Method method = clazz.getDeclaredMethod(methodName);
            //暴力反射
            method.setAccessible(true);
            //执行方法
            method.invoke(obj);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

Configuration file content:

className=cn.Reflect.Person
methodName=method2

Disadvantages: It is impossible to create objects with parameter constructors and execute methods with parameters. This is a disadvantage of the configuration file properties. After the annotations are introduced, the object will be created by simulating a Spring IOC creation rule

Guess you like

Origin blog.csdn.net/weixin_44706647/article/details/113481175