反射

反射

获取Class对象的三种方式

1
2
3
4
5
6
7
8
// 1. Object对象的getClass()方法
Class<?> obClass = new Object().getClass();

// 2. 类的静态class属性
Class<?> obClass = Object.class;

// 3. 通过Class类的静态forName(Stirng)方法加载
Class<?> obClass = Class.forName("com.package");

构造器

获取公有构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 获取所有公有构造方法
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}

// 获取公共的空参构造
Constructor<?> constructor1 = aClass.getConstructor();
System.out.println(constructor1);

// 获取公共的有参构造
Constructor<?> constructor2 = aClass.getConstructor(int.class, String.class);
System.out.println(constructor2);
// 通过该构造器创建对象
TestBean t1 = (TestBean) constructor1.newInstance();
System.out.println(t1);

获取私有构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
// 获取所有构造方法,包括私有
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}

// 获取私有的有参构造
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
// 强制访问私有构造器,通过该构造器创建对象
declaredConstructor.setAccessible(true);
TestBean t2 = (TestBean) declaredConstructor.newInstance(1);
System.out.println(t2);

方法

获取公有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取所有公有方法,包括父类的公有方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}

// 获取指定的带参公有方法
Method method = aClass.getMethod("setKey", String.class);
// 创建一个新对象
TestBean t1 = new TestBean();
// 通过反射调用对象中的方法,并传入方法所需的参数
method.invoke(t1, "八嘎雅鹿");
// 将会输出被修改后的t1
System.out.println(t1);

获取私有方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取所有方法,包括私有,但不会获取到父类方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}

// 获取指定的空参私有方法
Method test = aClass.getDeclaredMethod("getUid");
// 创建一个对象
TestBean t2 = new TestBean();
// 强制访问
test.setAccessible(true);
// 通过反射调用对象中的私有方法并获得方法的返回值
String result = (String) test.invoke(t2);

变量

获取公有变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 获取所有公有变量,包括父类的公有变量
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}

// 获取指定的公有变量对象
Field field = aClass.getField("name");
// 创建一个新对象
TestBean t1 = new TestBean();
// 通过反射修改对象中的变量值
field.set(t1, "小明");
System.out.println(t1.name);

// 获取指定的公有变量对象
Field field2 = aClass.getField("name");
// 创建一个对象并修改对象中的变量值
TestBean t2 = new TestBean();
t2.name = "小红";
// 通过反射得到对象中变量的值
String value = (String) field2.get(t2);
System.out.println(value);

获取私有变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 获取所有变量,包括私有变量,但不会获取到父类的变量
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}

// 获取指定的私有变量
Field declaredField = aClass.getDeclaredField("key");
// 创建一个新对象
TestBean t3 = new TestBean();
// 强制访问
declaredField.setAccessible(true);
// 通过反射修改对象中的变量值
declaredField.set(t3, "id");
System.out.println(t3.getKey());

// 获取指定的私有变量
Field declaredField = aClass.getDeclaredField("key");
// 创建一个新对象并修改对象中的变量值
TestBean t4 = new TestBean();
t4.setKey("aaa");
// 通过反射得到对象中变量的值
String key = (String) declaredField.get(t4);
System.out.println(key);

代理

代理模式通过创建一个代理对象来控制对原始对象的访问。代理模式涉及两个角色:代理角色真实角色,二者实现同一个接口。代理类负责代理真实类,为真实类提供控制访问的功能,真实类则完成具体的业务逻辑。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

如下,真实类先实现二者之间的接口

1
2
3
4
5
// 代理类与真实类中间的接口
public interface ArmoredWarrior {
void weapon();
void skill();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// 真实类
public class XingTian implements ArmoredWarrior{

@Override
public void weapon() {
System.out.println("火刑天烈剑");
}

@Override
public void skill() {
System.out.println("天烈斩");
}
}

静态代理

通过一个专用的代理类,实现真实类和代理类之间的接口,在调用代理类中的方法时,会执行前置增强、真实类对应方法以及后置增强,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ProxyClass implements ArmoredWarrior{
private final XingTian xingTian;

public ProxyClass(XingTian xingTian) {
this.xingTian = xingTian;
}

@Override
public void weapon() {
before();
xingTian.weapon();
after();
}

@Override
public void skill() {
before();
xingTian.skill();
after();
}

private void before() {
System.out.println("前置增强");
}

private void after() {
System.out.println("后置增强");
}
}

静态代理在使用时

1
2
3
4
5
XingTian xingTian = new XingTian();
ProxyClass proxyClass = new ProxyClass(xingTian);
// 调用代理类中的方法
proxyClass.weapon();
proxyClass.skill();

动态代理

通过java自带的java.lang.reflect.Proxy类来实现动态代理功能,在运行时动态生成一个代理对象,代理对象实现和原始类一样的接口,并将方法调用转发给真实对象,同时可以在方法调用前后执行额外的增强处理,通过反射机制实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 真实对象
ArmoredWarrior target = new XingTian();

// 代理类的类加载器,负责将动态生成的代理类加载到JVM中
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
// 指定代理类需要实现的接口列表,代理对象会实现这些接口的方法
Class<?>[] interfaces = new Class[]{ArmoredWarrior.class};
// 定义代理对象的方法调用逻辑
InvocationHandler handler = new InvocationHandler() {
/**
* 所有通过代理对象调用的方法,都会路由到 InvocationHandler.invoke()
* @param proxy 代理对象本身
* @param method 被调用的方法,代理对象和真实对象实现同一接口,所以此处的方法应该是二者都具备
* @param args 调用方法传递的参数
* @return 方法返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 真实对象的方法执行前的增强
System.out.println("前置增强");
// 真实对象的方法通过反射的方式被执行
Object result = method.invoke(target, args);
// 真实对象的方法执行后的增强
System.out.println("后置增强");
// 返回真实对象的方法执行结果
return result;
}
};

// 生成代理对象
ArmoredWarrior armoredWarrior = (ArmoredWarrior) Proxy.newProxyInstance(classLoader, interfaces, handler);
// 调用代理对象中的方法,将会执行:前置增强 -> 真实对象的对应方法 -> 后置增强
armoredWarrior.weapon();
armoredWarrior.skill();