反射
反射
在开发代码时,我们通常明确使用关键字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 = 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 { |
Constructor
构造方法用于创建一个Class的实例对象,反射API可以获取构造方法,包括方法的修饰符、参数类型、注解以及是否抛出异常等,构造方法不能继承。
Field
在反射API中,一个Field对象代表的是一个字段信息,通过java.lang.reflect.Field可以获取字段的名称、类型、修饰符、注解等,Filed可能是一个Java原始类型,也可能是对象引用类型。
Method
一个Method对象代表的是一个可被调用的普通方法(包括静态方法),java.lang.reflect.Method类提供
了获取方法的修饰符、返回值类型、参数类型、注解以及已经声明的抛出异常等信息。