反射
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
作用:
- 在运行中分析类的能力
- 在运行中查看和操作对象
- 基于反射自由创建对象
- 反射构建出无法直接访问的类
- set或者get到无法访问的成员变量
- 调用不可访问的方法
- 实现通用的操作代码
- 类似函数指针的功能
使用反射创建对象
String s = String.class.getConstructor(String.class).newInstance("str");
关键类
stateDiagram-v2 direction LR state "Class" as c1 c1 --> Field: getFields() getDeclaredFields() c1 --> Package: getPackage() c1 --> 接口(Class): getInterfaces() c1 --> Constructor: getConstructors() c1 --> Method: getMethods() getDeclaredMethods() c1 --> 修饰符(int): getModifiers() c1 --> 父类(Class): getSuperclass() c1 --> Annotation: getAnnotations()
Class
- cast:对象转型
- isInstance:类型确认
- isAssignableFrom:是否从某个类派生
CharSequence.class.isAssignableFrom(String.class)
类型的比较可以通过 instanceof 或者 isInstance接口来进行 这两个接口的比较是有考虑继承关系。
另外一种比较可以通过比较两个class对象,这种方式没有考虑继承关系。
安全性
反射提供的 AccessibleObject.setAccessible(boolean flag) 可以在运行时修改成员访问限制
在后续的版本中,Java 逐渐收紧了这个功能,只有在模块描述文件中开放权限才是合法的:
module MyEntities { // Open for reflection opens com.mycorp to java.persistence;}
当然,目前只是报一个警告,只是不知道在哪个版本中就会彻底关闭这个功能
应用
- 加载JDBC驱动
- 任意类型数组扩容
- 动态方法调用
- JSON序列化与反序列化
- Servlet创建
- ORM
- Bean容器
JAVA反射增强
功能
- get all subtypes of some type
- get all types/members annotated with some annotation
- get all resources matching a regular expression
- get all methods with specific signature including parameters, parameter annotations and return type
NoClassDefFoundError 和 ClassNotFoundException
- 如果编译时能找到这个类,但运行时找不到这个类,就抛出NoClassDefFoundError
- 如果通过Class.forName 进行加载找不到,则会抛出 ClassNotFoundException
反射的实现
一个通过本地方法来实现反射调用,即通过 JNI 来进行方法调用,另一个则使用了委派模式,即动态代理生成对具体类的具体方法方法调用
反射的开销
- 变长参数方法需要创建 Object 数组
- 基本类型的自动装箱、拆箱
- 方法内联优化失效