简介
反射是 Java 的特征之一。通过反射可以获得并调用任意一个类的所有属性和方法。反射可以在运行期间动态地创造对象、调用方法。
反射的主要使用
反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(例如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
反射是框架实现的灵魂
优缺点
- 优点:代码实现灵活、为各种框架的功能实现提供便利。
- 缺点:
- 滥用反射会额外消耗系统资源。
- 反射会忽略权限检查,增加安全问题。
基本用法
以 TargetObject
为例:
1 | public class TargetObject { |
获得 Class 的方式
通过
Class.forName()
方法传入类的全路径获取:1
2
3
4public static Class<?> forName(String className)
// xx.xxxx.TargetObject:类的全路径
Class alunbarClass1 = Class.forName("xx.xxxxx.TargetObject");通过具体类的
.class
属性获取:1
Class alunbarClass2 = TartgetObject.class;
通过实例对象的
instance.getClass()
方法获取:1
2TargetObject o = new TargetObject();
Class alunbarClass3 = o.getClass();
三种方法的区别在于:
Class.forName
不执行静态块和动态构造块。xxxx.class
执行静态块,但是不执行动态构造块。instance.getClass()
方法因为需要实力对象,所以静态块和动态块都会执行。
静态块仅在类加载时执行一次,若类已加载便不再重复执行;而动态构造块在每次 new 对象时均会执行。
创建实例对象
通过
Class
对象的newInstance()
方法创建实例对象:1
2
3
4
5/**
* 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
*/
Class<?> targetClass = TargetObject.class;
TargetObject targetObject = (TargetObject) targetClass.newInstance();通过创建
Class
对象的构造器对象,再调用构造器对象的newInstance()
方法来创建实例,即用制定的构造器来创建对象:1
2
3
4
5
6/**
* 获取 TargetObject 类的 Class 对象并且创建 TargetObject 类实例
*/
Class<?> targetClass = TargetObject.class;
Constructor<?> constructor = targetClass.getConstructor(String.class);
TargetObject targetObject2 = (TargetObject) constructor.newInstance("value");
方法获取及调用
方法的获取主要有以下三种方法:
getDeclaredMethods
:返回类或者接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但是不包括继承的方法。1
public Method[] getDeclaredMethods() throws SecurityException
getMethods
:返回某个类的所有公共方法,包括继承类的公用方法。1
public Method[] getMethods() throws SecurityException
getDeclaredMethod
:返回类的一个特定的方法,第一个参数为方法的名称,其余为方法的参数对应的Class对象。1
2public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
所有获取到的类方法都需要通过invode()
方法调用,以TargetObject
为例:
1 | /** |
成员变量的获取
getField()
:所有的公有变量信息。getDeclaredField()
:所有已声明的成员变量,但是不能得到父类的成员变量。1
2
3
4
5
6
7/**
* 获取指定参数并对参数进行修改
*/
Field field = targetClass.getDeclaredField("value");
// 取消安全检查
field.setAccessible(true);
field.set(targetObject, "new new value");
利用反射创造数组
利用反射创建数组的例子如下:
1 | public static void testArray() throws ClassNotFoundException { |
其中的Array
类为java.lang.reflect.Array
类,通过Array.newInstance()
创建数组对象。