Java反射

该笔记基于B站视频编写


1. 动态代理的思想分析

程序为什么需要代理?

代理在程序设计中有很重要的作用,它可以帮助我们更好地管理和扩展代码,同时也能提高代码的安全性和隐私性

使用代理的好处:

  • 降低程序复杂度
  • 易于业务扩展
  • 代码高内聚低耦合
  • 增强功能
  • 增强安全性和隐私性

代理就像中介公司一样,它通过接口来自动要代理那些方法
代理和被代理的类要实现同一个接口

image-20231224135938732

代码实现

定义一个接口(Star),里面放需要被代理的方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description: 把所有需要代理的方法都定义在接口中
*/
public interface Star {
// 唱歌
abstract String sing(String name);

// 跳舞
abstract void dance(String name);

}


创建一个需要被代理的类(BigStar),实现接口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
26
27
28
29
30
31
32
public class BigStar implements Star{
private String name;

public BigStar() {
}

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

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

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}


创建代理对象

java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法

1
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler 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
45
/**
* @description: 这个类用于创建代理
*/
public class ProxyUtil {

/**
* @description: 给一个明星对象创建一个代理
* 形参:被代理的明星对象
* 返回值:给明星创建代理
*
* 需求:
* 有人想请大明星唱歌
* 1. 获取代理对象
* 代理对象 = ProxyUtil.createProxy(大明星对象);
* 2. 调用代理的唱歌方法
* 代理对象。唱歌的方法();
*/
public static Star crateProxy(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 {
/**
* 参数一:代理的对象
* 参数二:要运行的方法
* 参数三:调用要运行的方法时,传入的参数
*/
if ("sing".equals(method)) {
System.out.println("准备话筒");
} else if ("dance".equals(method)) {
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
/**
* @description: 测试类
* 需求:
* 有人想请大明星唱歌
* 1. 获取代理对象
* 代理对象 = ProxyUtil.createProxy(大明星对象);
* 2. 调用代理的唱歌方法
* 代理对象。唱歌的方法();
*/
public class Test {
public static void main(String[] args) {
// 1. 获取代理对象
BigStar bigStar = new BigStar("鸡哥");
Star proxy = ProxyUtil.crateProxy(bigStar);
// 2. 调用唱歌的方法
String result = proxy.sing("只因你太美");
System.out.println(result);
}
}

运行结果

image-20231224145810847

2. 反射的概述

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

image-20231225115959606

Java 反射,就是在运行状态中

  • 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
  • 获取任意对象的属性,并且能改变对象的属性
  • 调用任意对象的方法
  • 判断任意一个对象所属的类
  • 实例化任意一个类的对象


3. 获取class对象

  • Class.forName(“全类名”)
  • 类名.class
  • 对象.getClass()

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
package com.zheng.myreflect;

public class Student {
private String name;
private int age;

public Student() {
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
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

public class MyReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
/**
* 获取class对象的三种方式
* 1. Class.forName("全类名")
* 2. 类名.class
* 3. 对象.getClass()
*/

// 第一种方式
// 最常见的
Class clazz1 = Class.forName("com.zheng.myreflect.Student");

// 第二种方式
// 一般在作为参数的时候使用
Class clazz2 = Student.class;

// 第三种方式
// 要有这个类的对象时才能使用
Student stu = new Student();
Class clazz3 = stu.getClass();

System.out.println(clazz1);
System.out.println(clazz1==clazz2);
System.out.println(clazz2==clazz3);
}
}

image-20231225135632247



4. 反射获取构造方式

Class类中用于获取构造方法的方法

  • Constructor<?>[]getConstructors():返回所有公共构造方法对象的数组
  • Constructor<?>[]getDeclaredConstructors():返回所有构造方法对象的数组
  • ConstructorgetConstructor(Class<?>…parameterTypes):返回单个公共构造方法对象
  • ConstructorgetDeclaredConstructor(Class<?>…parameterTypes):返回单个构造方法对象

Constructor类中用于创建对象的方法

  • T newInstance(Object… initargs):根据指定的构造方法创建对象
  • setAccessible(boolean flag):设置为true,表示取消访问检查

JAVA反射机制中,getModifiers()方法返回int类型值表示该字段的修饰符

修饰符 对应的int类型
public 1
private 2
protected 4
static 8
final 16
synchronized 32
volatile 64
transient 128
native 256
interface 512
abstract 1024
strict 2048

定义一个学生类,定义4个构造方法,其中两个公共的

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
public class Student {

private String name;
private int age;

public Student() {
}

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

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

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
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
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;

public class MyReflectDemo {

public static void main(String[] args) throws Exception {
// 1. 获取字节码文件对象
Class clazz = Class.forName("com.zheng.myrelfect2.Student");

// 获取构造方法
// 返回所有公共构造方法对象的数组
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con : cons1) {
System.out.println(con);
}
System.out.println("****************************");

// 返回所有构造方法对象的数组
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con : cons2) {
System.out.println(con);
}
System.out.println("****************************");

// 返回单个公共构造方法对象
Constructor con1 = clazz.getConstructor();// 无参
System.out.println(con1);
System.out.println("****************************");

Constructor con2 = clazz.getConstructor(String.class);// 有参
System.out.println(con2);
System.out.println("****************************");

// 返回单个构造方法对象
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
System.out.println("分割线******************************************************************");

// 获取构造方法对象的权限修饰等级
int modifiers = con3.getModifiers();
System.out.println(modifiers);
System.out.println("****************************");

// 获取构造方法对象的参数
Parameter[] parameters = con3.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
System.out.println("****************************");

// 用构造方法对象创建类
con3.setAccessible(true);// 临时取消权限验证(private),暴力反射
Student stu = (Student) con3.newInstance("正哥", 18);
System.out.println(stu);

}
}


运行结果

image-20231225144534739

5. 反射获取成员变量

Class类中用于获取成员变量的方式

  • Field[] getFields():返回所有公共成员变量对象的数组
  • Field[] getDeclaredFields():返回所有成员变量对象的数组
  • Field[] getField(String name):返回单个公共成员变量对象
  • Field getDeclaredField(String name):返回单个成员变量对象

Field类中用于创建对象的方法

  • void set(Object obj, Object value):赋值
  • Object get(Object obj):获取值

创建一个学生类,定义三个成员变量,一个公共的,两个私有的

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
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;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getGender() {
return gender;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}

public void setGender(String gender) {
this.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
import java.lang.reflect.Field;

public class MyReflectDemo {
public static void main(String[] args) throws Exception{

// 获取class字节码文件的对象
Class clazz = Class.forName("com.zheng.myrelflect3.Student");

// 获取所有成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("*****************************");

// 获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
System.out.println("*****************************");

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

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

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

// 获取成员变量的值,先有对象才有值
Student stu = new Student("正哥", 18, "男");
name.setAccessible(true);// 临时取消访问权限
String nameValue = (String) name.get(stu);
System.out.println(nameValue);
System.out.println("*****************************");

// 修改对象里面记录的值
name.set(stu, "正哥学Java");
System.out.println(stu);
}
}


测试结果

image-20231225152725571

6. 反射获取成员方法

Class类中用于获取成员方法的方法

  • Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的(包含父类的)
  • Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
  • Method[] getMethod(String name, Class<?>…parameterTypes):返回单个公共成员方法对象
  • Method[] getDeclaredMethod(String name, Class<?>…paramenterTypes):返回单个成员方法对象

Method类中用于创建对象的方法

Object invoke(Object obj, Object…args):运行方法

  • 参数一:用obj对象调用该方法
  • 参数二:调用方法的传递的参数(没有就不用写)
  • 返回值:方法的返回值(没有就不用写)

定义一个student类,有两个成员方法,一个是公共方法sleep(),一个是私有方法eat()

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
package com.zheng.myrelflect4;

import java.io.IOException;

public class Student {
private String name;
private int age;

public Student() {
}

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

public String getName() {
return name;
}

public void sleep() {
System.out.println("睡觉");
}

private String eat(String something) throws NullPointerException{
System.out.println("再吃" + something);
return "太好吃了";
}

public void setName(String name) throws IOException {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.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
package com.zheng.myrelflect4;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class MyReflectDemo {

public static void main(String[] args) throws Exception{
// 获取class字节码文件对象
Class<?> clazz = Class.forName("com.zheng.myrelflect4.Student");

// 获取所有的公共方法对象(包括父类的)
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("分割线********************分割线");

// 获取所有的方法对象(包括所有的,不包括父类的)
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("分割线********************分割线");

// 获取指定的单一方法
// 第一个参数是方法名,第二个参数是方法的参数类型
Method method = clazz.getDeclaredMethod("eat",String.class);
System.out.println(method);
System.out.println("*****************************");

// 获取方法的修饰符
int modifiers = method.getModifiers();
System.out.println(modifiers);

// 获取方法的名字
String name = method.getName();
System.out.println(name);
System.out.println("*****************************");

// 获取方法的形参
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}

// 获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
System.out.println("*****************************");

// 方法运行
Student stu = new Student();
method.setAccessible(true);
// 参数一stu:表示方法的调用者
// 参数二“汉堡包”:表示在调用方法的时候传递的实际参数
String result = (String) method.invoke(stu, "汉堡");
System.out.println(result);
}
}

测试结果

image-20231225213808019

image-20231225214013575



Java反射
https://lzhengjy.github.io/2023/12/23/Java反射/
作者
Zheng
发布于
2023年12月23日
许可协议