Java 反射机制
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
反射主要用到的 API:
- java.lang.Class:代表一个类。
- java.lang.reflect.Method:类的方法。
- java.lang.reflect.Field:类的成员变量。
- java.lang.reflect.Constructor:类的构造器。
- 等等
Class 类
加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。这个对象就像一面镜子,透过这个镜子看到类的结构。
常用方法
Class 类常用方法如下:
反射的举例:
通过反射,可以访问类的私有结构(构造器、属性、方法)。
1 | // 实例化 Class 类对象 |
获取 Class 类实例方法
获取 Class 类实例方法:
- 类的 class 属性:若已知具体的类,通过类的class属性获取。
- 实例的 getClass 方法:已知某个类的实例,调用该实例的 getClass() 方法获取 Class 对象。
- Class 类的 forName 方法:已知一个类的全类名,可通过 Class 类的静态方法 forName() 获取,可能抛出 ClassNotFoundException 异常。
- 类加载器 ClassLoader:使用类加载器 ClassLoader 的 loadClass 方法。
创建运行时类的对象
创建运行时类的对象有两种方法:
- Class 对象的 newInstance 方法:这个方法要求类必须有一个无参数的构造器(InstantiationException),并且类构造器的访问权限足够(IllegalAccessException)。
- Class 对象的 getDeclaredConstructor(Class parameterTypes) 方法:用这个方法可以获取指定形参类型的构造器。
1 | // 根据全类名获取对应的Class对象 |
调用运行时类的指定结构
Class 类可以获取方法(Method)、构造器(Constructor)、属性(Field)、权限(Modifier)、接口(Interface)、注解(Annotation)等。
getXxx:返回 Class 对象中权限为 public 的 Xxx(包括父类中声明的)。
getDeclaredXxx:返回 Class 对象中声明的所有 Xxx(包括所有权限,但是不包括父类中的,只包括类本身声明的)。
setAccessible 方法
Method 和 Field、Constructor 对象都有 setAccessible() 方法。参数值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。
- 使得原本无法访问的私有成员也可以访问。
代理设计模式
在之前介绍过代理设计模式,核心就是代理类和被代理类实现同一个接口。代理模式又分为:
- 静态代理模式。
- 动态代理模式。
静态代理模式
静态代理模式中,代理类是已经定义好的。
1 | package com.dawn.java; |
动态代理
动态代理借助 Java API java.lang.reflect.Proxy 类完成,Proxy 是专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
实现方法
动态代理的实现步骤:
- 创建一个实现接口 InvocationHandler 的类,它必须实现 invoke 方法,以完成代理的具体操作。
1 | class MyInvocationHandler implements InvocationHandler { |
- 定义声明被代理类。
- 利用 Proxy.newProxyInstance 方法,**newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)**,生成一个动态代理对象。
1 | class ProxyFactory { |
动态代理与 AOP
AOP(Aspect Orient Programming)面向切面编程,主要解决的是在执行目标方法之前、之后插入一些通用处理。
在 InvocationHandler 实现类中,重写的 invoke 方法中,在执行被代理对象的目标方法前后,可以加上一些通用的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class MyInvocationHandler implements InvocationHandler {
private Object obj; // 使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 通用的处理 ...
Object returnVal = method.invoke(obj, args);
// 通用的处理 ...
return returnVal;
}
}