何为反射
Oracle 的官方文档中是这么解释反射的:
“Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.”
具体而言,反射 (Reflection) 提供了一种在程序运行时动态获取 Class 方法、属性、接口等内部信息的机制。通过反射可以让在程序运行期实例化对象、调用方法、获取属性,即使方法或属性是 private 的也可以通过反射机制调用。
反射原理
篇幅和精力有限,只看了获取 Class 、获取与调用 Method 和获取 Field 的源码。
反射获取 Class 原理(Class.forName()方法)
1 |
|
反射获取 Method 原理(getDeclaredMethod()方法)
1 |
|
反射调用 Method 原理(invoke()方法)
1 |
|
反射获取 Field 原理(getField()方法)
1 |
|
反射的使用
反射获取 Class
1 | // 在使用Class.forName()方法时必须提供一个类的全名 |
反射创建对象
通过反射创建类对象主要有两种方式:
- 通过 Class 的
newInstance()
方法。 - 通过 Constructor 的
newInstance()
方法。
1 | Class aClass = Class.forName("com.test.reflectiontest.aClass"); |
1 | Class aClass = Class.forName("com.test.reflectiontest.aClass"); |
通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参构造方法。
1 | // 调用有参数构造方法进行对象的初始化 |
反射获取方法
1 | Method method = aClass.getMethod("someMethod",returnType.class); |
1 | // 若方法为private类型,则 |
反射获取属性
1 | Field field = aClass.getField("someField"); |
1 | // 若属性为private类型,需要用getDeclaredField()方法 |
反射获取父类
1 | Class superClass = aClass.getSuperclass(); |
反射获取修饰符
1 | int modifiers = aClass.getModifiers(); |
1 | // 检查修饰符类型 |
反射的应用场景
- Idea 等 IDE 的自动补全功能,通过反射机制 IDE 可以自动把对象的方法和属性都显示出来。
- JDBC 中通过
Class.forName()
动态加载 DB 的驱动。 - Spring 中通过 XML 实现注入 Bean。
- 序列化与反序列化中的自定义序列化会使用反射来检查对象是否实现了
writeObject()
和readObject()
两个方法。
反射性能慢的原因
反射需要按名字来检索类和方法,有一定的时间开销。
反射涉及类型的动态处理,某些虚拟机无法执行性能优化。
因此,同样功能的反射代码与非反射代码相比性能要慢,所以在性能敏感的应用中要避免使用反射。