1、什么是反射
Java在运行状态中,对于任何一个类,都可以获取到这个类的属性和方法,对于任何一个对象,都能调用这个对象的方法和属性(包括私有的)。这种动态获取信息和动态调用方法的机制就叫反射。
很多人会说我直接new一个对象不就完了么,干嘛非得通过反射来获取对象。因为new属于静态编译,而反射属于动态编译。反射它只有在程序运行时它才会去获取对象,从这点上可以看出反射的强大。
要理解发射在Java中的原理,首先要知道类型信息在运行时是如何表示的。其实,这是由Class对象来完成的,它包含了所有与类有关的信息,类的属性、方法、构造器、修饰符、实现类、子类和父类等等。程序运行时,每个类都会产生一个Class对象,保存在.class文件中。所有类都是在对Class对象第一次使用时,记载到JVM中的。
这里,需要重点注意,什么是运行时?可以联想到注解。注解有三个生命周期,分别是SOURCE、CLASS和RUNTIME。其实一样的,这里RUNTIME就对标着运行时。
2、获取Class的三种方式
方式 | 备注 |
Class,forName("全限定类名") | 静态方法 |
实例对象.getClass() | |
类名.calss |
// 获取Class的三种方式
Class aClass1 = Class.forName("com.teligen.backendproject.reflection.Person");
Class aClass2 = new Person().getClass();
Class aClass3 = Person.class;
*注意*:以上三种方式都是返回Class类型。
3、反射相关的重要的类有哪些
类 | 含义 |
---|---|
java.lang.reflect.Class | 代表整个字节码,代表一个类型,代表一个类 |
java.lang.refelct.Constroctor | 代表字节码中的构造器字节码,代表类中的构造器 |
java.lang.Field | 代表字节码中的属性字节码,代表类中的成员 变量(实例变量和静态变量) |
java.lang.Method | 代表字节码中的方法字节码,代表类中的方法 |
java.lang.Modify | 代表字节码中的修饰符字节码,代表类中的修饰符 |
*注意*:要先获取到Class,才能获取到Constructor,Field,Methd...
例子,通过反射获取整个类的信息
package com.teligen.backendproject.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @Author:
* @Date: 2022/03/15
*/
public class ReflectionDemo {
public static void main(String[] args) throws ClassNotFoundException {
//获取整个类
Class c = Class.forName("java.lang.Integer");
//获取所有的属性?
Field[] fs = c.getDeclaredFields();
//定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
}
sb.append("}");
System.out.println(sb);
}
}
4、思考
使用反射,在程序运行时获取类的信息,其实就是为了让我们写的代码更具有通过用性和灵活性。用深刻理解反射,就先抛弃我们日常写的业务代码,以更高的维度或者更抽象的思维去看待我们所写的“工具”。所谓工具,在单个系统叫做"Utils",在多个系统使用打成jar包叫做”组件“,组件继续发展壮大就叫”框架“。
一个好用的”工具“是需要兼容各种情况的,你肯定不知道使用该”工具“的用户传入的是什么对象,但你需要帮它得到需要的结果。
例如SpringMVC你在方法上写上对象,传入的参数就会帮你封装到对象上;Mybaties可以让我们只写接口,不写实现类,也能执行SQL;在类上家伙是那个@Component注解,Spring就会帮你创建对象。。。这些通通都有反射的身影:约定大于配置,配置大于编码。
通过”约定“的姿势,使用反射在程序运行时获取相应类的信息(毕竟作为一个”工具“,真不知道你到底传入的是什么对象),实现代码功能的通用性和灵活性。