反射

在开发代码时,我们通常明确使用关键字new创建对象,然后调用对象的某个具体方法,这种方式在
程序运行前就已经确定了对象的类型、方法、字段等。有些功能场景下,需要动态获取并修改对象运
行时行为,这就是Java反射的作用,通过Java反射,可以动态获取对象的方法(包括构造方法)、属
性、注解、修饰符等,任何东西在反射面前都是透明的。

反射的一些缺点

  • 性能相对较低:没有经过编译优化,需要动态即时解析。
  • 有安全⻛险:私有方法或属性,可通过反射强制进入。
  • 难以维护:修改类的方法或字段时,部分反射代码功能错误在编译时无法检查

虽然反射有一些缺点,但是它的应用场景也非常广泛。

  • 动态代理,字节码增强
  • 框架设计,解耦、提升扩展性
  • 序列化与反序列化
  • JavaBean
  • IDE工具

java.lang.reflect包提供了大量的反射API,主要的一些核心类包括Method、Field、Constructor等。
JVM给每个对象提供了一个java.lang.Class实例,相同类型的实例对象得到的是同一个Class对象,
Class是反射API操作的入口。

获取Class对象

Java提供了三种方式获取Class对象

Object.getClass()

.class 语法

当有一个有效的类型,但是并没有对应的类型实例时,直接在类型实例后面增加.class语法,即可获取Class对象。

boolean b;
Class c = b.getClass(); // 编译错误
Class c = boolean.class; // 正确

获取Integer的Class对象

Class c = java.lang.Integer.class;

Class.forName()

这种方式必须知道类的全类名,然后通过Class的静态方法forName()获取,全类名不存在,则会抛出ClassNotFoundException异常,不能使用这种方式获取Java原始类型的Class对象。

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

Class.forName经常用于让JVM主动加载某个Class,如加载MySQL的驱动类。

Class.forName("com.mysql.jdbc.Driver");

这种方式作用是什么?
类加载之后,接着会进行初始化,其中包括类的静态代码块的执行,MySQL的Driver类就是通过静态代码块,完成了一个非常重要的操作,即把MySQL的驱动注册到JDBC驱动管理器中。

static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");

Constructor

构造方法用于创建一个Class的实例对象,反射API可以获取构造方法,包括方法的修饰符、参数类型、注解以及是否抛出异常等,构造方法不能继承。

Field

在反射API中,一个Field对象代表的是一个字段信息,通过java.lang.reflect.Field可以获取字段的名称、类型、修饰符、注解等,Filed可能是一个Java原始类型,也可能是对象引用类型。

Method

一个Method对象代表的是一个可被调用的普通方法(包括静态方法),java.lang.reflect.Method类提供
了获取方法的修饰符、返回值类型、参数类型、注解以及已经声明的抛出异常等信息。