参考视频:
https://www.bilibili.com/video/BV1ke4y1w7yn/?p=7&spm_id_from=pageDriver&vd_source=c0cc92a482393bb63596629a72e3fc71

动态代理

  1. 为什么需要代理
    代理可以无侵入式的给对象增强其他的功能
    调用者 -> 代理 -> 对象
  2. 代理长什么样?
    代理里面就是对象要被代理的方法
  3. Java通过什么来保证代理的样子?
    通过接口保证 后面的对象和代理需要实现同一个接口
    接口中就是被代理的所有方法

动态代理的代码实现
代理类的实现

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
*
* 类的作用:
* 创建一个代理
*
* 需求:
* 外面的人想要大明星唱一首歌
* 1. 获取代理对象
* 代理对象 = ProxyUtil.createProxy(大明星的对象)
* 2.再调用代理的唱歌方法
* 代理对象,唱歌的方法("xxx")
*/
public class ProxyUtil {
/**
* 方法作用: 给一个对象 创建一个代理
* 形参: 被代理的对象
* 返回值: 为对象创建的代理
* @param bigStar
* @return
*/
public static Star createProxy(BigStar bigStar){

/**
* java.lang.reflect.Proxy; 创建代理
*
*/
Star star = (Star) Proxy.newProxyInstance(
// 用于指定类加载器 去加载生成的代理类
ProxyUtil.class.getClassLoader(),
// 指定接口 这些接口用于指定生成的代理长什么样 也就是有那些方法
// 能代理的方法都在接口中
new Class[]{Star.class},
// 指定生成的代理都要干啥
new InvocationHandler() {
/**
*
* @param proxy the proxy instance that the method was invoked on
* 代理的对象
*
* @param method the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
* 要运行的方法 例如: sing
*
* @param args an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
* 调用方法 传递的实参
*
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("sing".equals(method.getName())){
System.out.println("准备话筒 收钱");
}else if ("dance".equals(method.getName())){
System.out.println("准备场地 收钱");
}

// 去找大明星开始唱歌或跳舞
// 代码的表现形式 调用大明星里面的唱歌或者跳舞的方法
return method.invoke(bigStar,args);
}
}
);

return star;
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public class Test {
/**
* 需求:
* 外面的人想要大明星唱一首歌
* 1. 获取代理对象
* 代理对象 = ProxyUtil.createProxy(大明星的对象)
* 2.再调用代理的唱歌方法
* 代理对象,唱歌的方法("xxx")
*/

public static void main(String[] args) {
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);

String result = proxy.sing("及你太美");
System.out.println(result);
}
}

反射

反射允许对封装类的字段 方法和构造函数的信息进行便编程访问

获取class对象的三种方式

三种方式的代码示例:

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
public class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {

/**
* 获取class对象的三种方式
* 1. Class.forName("全类名")
* 2. 类名.class
* 3. 对象.getClass();
*/

// 1. 第一种方式
// 全类名: 包名 + 类名
// 最为常用
Class<?> clazz1 = Class.forName("Student");

// 2. 第二种方式
// 一般更多当作参数进行传递
Class<Student> clazz2 = Student.class;

// 3. 第三种方式
// 当我们已经有了这个类的对象时 才可以使用
Student s = new Student();
Class<? extends Student> clazz3 = s.getClass();

// 输出均为true 证明三种方式获取的字节码文件是一样的
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
}
}

利用反射获取构造方法

代码示例

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1. 获取class字节码文件对象
Class<?> clazz1 = Class.forName("Student2");

// 2. 获取构造方法
// 获取所有公共构造
Constructor<?>[] cons = clazz1.getConstructors();

for (var con: cons){
System.out.println(con);
}


// 获取所有构造 包括私有 保护
Constructor<?>[] cons2 = clazz1.getDeclaredConstructors();

for (var con: cons2){
System.out.println(con);
}

// 获取单个构造
Constructor<?> con1 = clazz1.getDeclaredConstructor(String.class);
System.out.println(con1);

// 获取多个构造
Constructor<?> con2 = clazz1.getDeclaredConstructor(String.class, int.class);
// 获取构造方法的权限修饰符
int modifiers = con2.getModifiers();
System.out.println(modifiers);

Parameter[] parameters = con2.getParameters();
for (var parameter: parameters){
System.out.println(parameter);
}

// 暴力反射: 表示临时取消权限校验 可以获取私有对象
con2.setAccessible(true);
// 使用构造创建对象
Student2 stu = (Student2) con2.newInstance("xx", 22);
System.out.println(stu.toString());
}
}

利用反射获取成员变量

代码示例

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
35
import java.lang.reflect.Field;

public class MyReflectDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class<?> clazz = Class.forName("Student3");
// 获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);

// 获取权限修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);

// 获取成员变量的名字
String n = name.getName();
System.out.println(n);


// 获取成员变量的数据类型
Class<?> type = name.getType();
System.out.println(type);

// 获取成员变量记录的值
Student3 s = new Student3("xx",22,1);
name.setAccessible(true);
Object value = name.get(s);
System.out.println(value);

// 修改对象里面记录的值
name.set(s,"yy");
value = name.get(s);
System.out.println(value);
}
}

利用反射获取成员方法