2025.04.29

Java 反射&动态代理

一、反射

1.1 反射的概念

  • 反射允许对成员变量、成员方法和构造方法的信息进行编程访问

1.2 获取class对象的三种方式

  1. Class.forName(“全类名”);
    • 在源代码阶段使用
    • 最为常用
  2. 类名.class
    • 在加载阶段使用
    • 一般更多的是当做参数进行传递
  3. 对象.getClass();
    • 在运行阶段使用
    • 当我们已经有了这个类的对象时,才可以使用

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
public static void main(String[] args) throws ClassNotFoundException {

// 1. Class.forName("全类名")
// 全类名:包名+类名
// 使用copy reference获取
Class clazz1 = Class.forName("Student");

// 2. 类名.class
Class clazz2 = Student.class;

// 3. 对象.getClass
Student s = new Student();
Class clazz3 = s.getClass();

System.out.println(clazz1); // class Student
System.out.println(clazz1 == clazz2); // true
System.out.println(clazz2 == clazz3); // true
}
}

1.3 反射获取构造方法

  • Class类中用于获取构造方法的方法
    • Constructor<?>[] getConstructors():获取所有公共构造方法对象的数组
    • Constructor<?>[] getDeclaredConstructors():获取所有构造方法对象的数组,包括私有的
    • Constructor<T> getConstructor(Class<?>… parameterTypes):获取单个公共构造方法
    • Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes):获取单个构造方法,包括私有的
  • Constructor类中用于创建对象的方法
    • T newInstance(Object… initargs):根据指定的构造方法创建对象
    • setAccessible(boolean flag):设置为true表示取消访问检查

示例:

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
// Student类
public class Student {
private String name;
private int age;


public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

protected Student(String name) {
this.name = name;
}

private Student(int age) {
this.age = age;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
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
import java.lang.reflect.Constructor;

public class ConstructorDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {

Class clazz = Class.forName("Student");

System.out.println("------------cons1------------");
Constructor[] cons1 = clazz.getConstructors();
for (Constructor cons : cons1) {
System.out.println(cons);
}

System.out.println("------------cons2------------");
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor cons : cons2) {
System.out.println(cons);
}

System.out.println("------------con1------------");
Constructor con1 = clazz.getDeclaredConstructor();
System.out.println(con1);

System.out.println("------------con2------------");
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);

System.out.println("------------con3------------");
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);

System.out.println("------------con4------------");
Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con4);

int modifiers = con4.getModifiers(); // 权限修饰符
System.out.println("modifiers: " + modifiers);

// 暴力反射
con4.setAccessible(true);
Student stu = (Student) con4.newInstance("张三", 23);

System.out.println(stu);
}
}


// 输出:
// ------------cons1------------
// public Student()
// public Student(java.lang.String,int)
// ------------cons2------------
// public Student()
// public Student(java.lang.String,int)
// protected Student(java.lang.String)
// private Student(int)
// ------------con1------------
// public Student()
// ------------con2------------
// protected Student(java.lang.String)
// ------------con3------------
// private Student(int)
// ------------con4------------
// public Student(java.lang.String,int)
// modifiers: 1
// Student{name = 张三, age = 23}

1.4 反射获取成员变量

  • Class类中用于获取成员变量的方法
    • Field[] getFields():获取所有公共成员变量对象的数组
    • Field[] getDeclaredFields():获取所有成员变量对象的数组,包括私有的
    • Field getField(String name):获取单个公共成员变量对象
    • Field getDeclaredField(String name):获取单个成员变量对象,包括私有的
  • Field类中用于创建对象的方法
    • Object get(Object obj):获取指定对象的成员变量值
    • void set(Object obj, Object 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
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
// Student类
public class Student {
private String name;
private int age;
public String gender;


public Student() {
}

public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}

/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}

/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}
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
import java.lang.reflect.Field;

public class FiledDemo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class clazz = Class.forName("Student");

System.out.println("----------getFields----------");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}

System.out.println("----------getDeclaredFields----------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}

System.out.println("----------getDeclaredField----------");
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);

Student stu = new Student("张三", 23, "男");
System.out.println(stu);
name.setAccessible(true);
Object value = name.get(stu);
System.out.println(value);

// 修改对象中的值
name.set(stu, "李四");
System.out.println(stu);
}
}


// 输出:
// ----------getFields----------
// public java.lang.String Student.gender
// ----------getDeclaredFields----------
// private java.lang.String Student.name
// private int Student.age
// public java.lang.String Student.gender
// ----------getDeclaredField----------
// private java.lang.String Student.name
// 2
// name
// class java.lang.String
// Student{name = 张三, age = 23, gender = 男}
// 张三
// Student{name = 李四, age = 23, gender = 男}

1.5 反射获取成员方法

  • Class类中用于获取成员方法的方法
    • Method[] getMethods():获取所有公共成员方法对象的数组,包括父类的所有公共方法
    • Method[] getDeclaredMethods():获取所有成员方法对象的数组,包括私有的
    • Method getMethod(String name, Class<?>… parameterTypes):获取单个公共成员方法对象
    • Method getDeclaredMethod(String name, Class<?>… parameterTypes):获取单个成员方法对象,包括私有的
  • Method类中用于创建对象的方法
    • Object invoke(Object obj, Object… args):调用指定对象的成员方法
    • 参数一:用obj对象调用该方法
    • 参数二:调用方法的传递的参数(如果没有就不写)
    • 返回值:方法的返回值(如果没有就不写)

1.6 反射的作用

  1. 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
  2. 结合配置文件,动态地创建对象并调用方法

1.7 练习1:保存信息

  • 需求:对于任意一个对象,都可以把对象所有的字段名和值保存到文件中去
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
import java.io.*;
import java.lang.reflect.Field;

public class Main {
public static void main(String[] args) throws IOException, IllegalAccessException {

Student s = new Student("小A", 23, '女', 167.5, "睡觉");
Teacher t = new Teacher("波妞", 10000);

saveObject(t);
}

// 把对象里面的所有成员变量名和值保存在本地文件中
public static void saveObject(Object obj) throws IOException, IllegalAccessException {
Class clazz = obj.getClass();

Field[] declaredFields = clazz.getDeclaredFields();

BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

for (Field f : declaredFields) {
f.setAccessible(true);
String name = f.getName();
Object value = f.get(obj);
bw.write(name + "=" + value);
bw.newLine();
}
bw.close();
}
}

1.8 练习2:跟配置文件结合动态创建

  • 需求:反射可以跟配置文件结合的方式,动态创建对象,并调用方法
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
// Student类
public class Student {
private String name;
private int age;


public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public void study() {
System.out.println("学生正在学习");
}

/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}

/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}

/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}

public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
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
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Main {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

Properties prop = new Properties();
FileInputStream fis = new FileInputStream("D:\\Java Study\\heima\\ReflectDemo\\Test2\\src\\prop.properties");
prop.load(fis);
fis.close();
System.out.println(prop);

String classname = (String) prop.get("classname");
String methodname = (String) prop.get("method");

Class clazz = Class.forName(classname);

Constructor con = clazz.getDeclaredConstructor();
Object o = con.newInstance();
Method method = clazz.getDeclaredMethod(methodname);
method.invoke(o);
}
}
1
2
classname=Student
method=study

二、动态代理

2.1 动态代理的概念

  • 动态代理是指在运行时创建一个代理对象,并将其与目标对象关联起来,从而实现对目标对象的访问和控制。动态代理可以用于实现AOP(面向切面编程)、权限控制、事务管理等功能。动态代理的实现通常依赖于Java反射机制和接口的使用。
  • 特点:无侵入式地给代码增加额外的功能
  • 代理是一个接口,内部是对象要被代理的方法

2.2 动态代理的实现步骤

  • java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
  • public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    • loader:用于指定用哪个类加载器,去加载生成的代理类
    • interfaces:指定接口,这些接口用于指定生成的代理长什么样,也就是有哪些方法
    • h:用来指定生成的代理对象要干什么事情

示例:

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
// BigStar类
public class BigStar implements Star {
private String name;

public BigStar() {
}

public BigStar(String name) {
this.name = name;
}

// 唱歌
@Override
public String sing(String name) {
System.out.println(this.name + "正在唱" + name);
return "谢谢";
}

// 跳舞
@Override
public void dance() {
System.out.println(this.name + "正在跳舞");
}

/**
* 获取
* @return name
*/
public String getName() {
return name;
}

/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}

public String toString() {
return "BigStar{name = " + name + "}";
}
}
1
2
3
4
5
6
7
8
// Star接口
public interface Star {
// 唱歌
public abstract String sing(String name);

// 跳舞
public abstract void dance();
}
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
// ProxyUtil类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil {
// 用于给BigStar生成代理

/*
需求:外面的人想要大明星唱歌
1. 获取代理的对象
代理对象 = ProxyUtil.createProxy(大明星的对象);
2. 再调用代理的唱歌方法
代理对象.唱歌的方法();
*/


public static Star createProxy(BigStar bigStar) {

Star star = (Star) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(), // 固定格式
new Class[]{Star.class}, // 指定接口
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
参数一:代理的对象
参数二:要运行的方法
参数三:调用sing方法时传递的参数
*/
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
21
22
23
24
25
// Main类
import DynamicproxyDemo1.BigStar;
import DynamicproxyDemo1.ProxyUtil;
import DynamicproxyDemo1.Star;

public class Main {
public static void main(String[] args) {

BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.createProxy(bigStar);

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

proxy.dance();
}
}


// 输出:
// 准备话筒,收钱
// 鸡哥正在唱只因你太美
// 谢谢
// 准备场地,收钱
// 鸡哥正在跳舞