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:
- Use the .class method to get a class
- Use the getClass() method of the Object class
- 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