反射
概述
可以用反射来获取类中的所有信息
获取class对象的三种方式
Class.forName(“全类名”)
全类名:包名 + 类名
1
2
3
4
5
6
|
try {
Class clazz = Class.forName("com.yuanyu.Student");
System.out.println(clazz);// class com.yuanyu.Student
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
|
在idea中,全类名可以直接复制

类名.class
1
|
System.out.println(Student.class);// class com.yuanyu.Student
|
对象.getClass()
1
2
|
Student student = new Student();
System.out.println(student.getClass());// class com.yuanyu.Student
|
以上三种方式获取的字节码文件对象是一样的
获取构造方法
获取构造方法
Class类中用于获取构造方法的方法
Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象
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
|
try {
// 1. 获取class字节码文件对象
Class clazz = Class.forName("com.yuanyu.Student");
// 2. 获取构造方法
// 2.1 获取所有public修饰的构造方法
Constructor[] constructors1 = clazz.getConstructors();
for (Constructor constructor : constructors1) {
System.out.println(constructor);
}
System.out.println("============================================");
// 2.2 获取所有构造方法(包括:private、protected等)
Constructor[] constructors2 = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors2) {
System.out.println(constructor);
}
System.out.println("============================================");
// 2.3 获取指定参数类型的public构造方法
Constructor constructor1 = clazz.getConstructor(String.class, int.class);
System.out.println(constructor1);
// Constructor constructor2 = clazz.getConstructor(int.class);
// System.out.println(constructor2);// 会报错
Constructor constructor3 = clazz.getConstructor();
System.out.println(constructor3);
System.out.println("============================================");
// 2.4 获取指定参数类型的构造方法(包括:private、protected等)
Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
} catch (Exception e) {
e.printStackTrace();
}
|
输出结果:
其中,我的Student类如下
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
|
package com.yuanyu;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
protected Student(String name) {
this.name = name;
}
private Student(int age) {
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
|
try {
Class clazz = Class.forName("com.yuanyu.Student");
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
// 获取权限修饰符
int modifiers = declaredConstructor.getModifiers();
System.out.println(modifiers);// 1(表示获取的这个构造是public的,具体数字表示什么,可以上网查阅)
// 获取参数列表
Parameter[] parameters = declaredConstructor.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
/**
* 输出:
* java.lang.String name
* int age
*/
}
// 暴力反射:临时修改访问权限,使得私有的构造方法可以被访问
// 如果是私有的构造方法,可以临时修改访问权限,使得私有的构造方法可以被访问
declaredConstructor.setAccessible(true);
Student student = (Student) declaredConstructor.newInstance("张三", 18);
System.out.println(student);// Student{name='张三', age=18} (如果输出的是com.yuanyu.Student@5a14e60d这种,说明没有重写toString方法)
} catch (Exception e) {
e.printStackTrace();
}
|
获取成员变量
获取成员变量
Class类中用于获取成员变量的方法
Field [] getFields ():返回所有公共成员变量对象的数组
Field [] getDeclaredFields ():返回所有成员变量对象的数组
Field getField (String name):返回单个公共成员变量对象
Field getDeclaredField (String name):返回单个成员变量对象
获取成员变量的用法与获取构造方法的用法类似,此处省略
用途
获取成员变量的修饰符、成员变量名等,具体不多赘述
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
|
try {
Class clazz = Class.forName("com.yuanyu.Student");
// 获取name字段
Field field = clazz.getDeclaredField("name");
System.out.println(field);// private java.lang.String com.yuanyu.Student.name
// 获取权限修饰符
int modifiers = field.getModifiers();
System.out.println(modifiers);// 2(表示获取的这个字段是private的,具体数字表示什么,可以上网查阅)
// 获取成员变量名
String name = field.getName();
System.out.println(name);// name
// 获取数据类型
Class<?> type = field.getType();
System.out.println(type);// class java.lang.String
// 获取成员变量记录的值
Student student = new Student("张三", 18);
field.setAccessible(true);
Object o = field.get(student);
System.out.println(o);// 张三
// 修改对象中记录的值
field.set(student, "李四");
System.out.println(student);// Student{name='李四', age=18}
} catch (Exception e) {
e.printStackTrace();
}
|
获取成员方法
获取成员方法
Method [] getMethods ():返回所有公共成员方法对象的数组,包括继承的
Method [] getDeclaredMethods ():返回所有成员方法对象的数组,不包括继承的
Method getMethod (String name, Class... parameterTypes):返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class... parameterTypes):返回单个成员方法对象
1
2
3
4
5
6
7
8
9
10
11
12
|
try {
// 获取class字节码文件对象
Class clazz = Class.forName("com.yuanyu.Student");
// 获取指定的单一方法
// 后面的参数可以区分不同的同名方法
Method eat1 = clazz.getDeclaredMethod("eat", String.class, int.class);
System.out.println(eat1);// private void com.yuanyu.Student.eat(java.lang.String, int)
Method eat2 = clazz.getDeclaredMethod("eat", String.class);
System.out.println(eat2);// private void com.yuanyu.Student.eat(java.lang.String)
} catch (Exception e) {
e.printStackTrace();
}
|
为了演示,在Student类中加入了下面三个方法
1
2
3
4
5
6
7
8
9
10
11
12
|
public String sleep() {
System.out.println("睡觉中~~~");
return "别打扰";
}
private void eat(String food) throws IOException, InterruptedException, NullPointerException {
System.out.println("我要吃" + food);
}
private void eat(String food, int num) {
System.out.println("我要吃" + num + "个" + food);
}
|
用途
获取方法的修饰符、名字、形参、返回值、抛出的异常等,具体不多赘述
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
|
try {
// 获取class字节码文件对象
Class clazz = Class.forName("com.yuanyu.Student");
// 获取指定的单一方法
Method method = clazz.getDeclaredMethod("eat", String.class);
// 获取权限修饰符
int modifiers = method.getModifiers();
System.out.println(modifiers);// 2(表示获取的这个方法时private的,具体数字表示什么,可以上网查阅)
// 获取方法名
String name = method.getName();
System.out.println(name);// eat
// 获取形参
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);// java.lang.String food
}
// 获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
/**
* 输出:
* class java.io.IOException
* class java.lang.InterruptedException
* class java.lang.NullPointerException
*/
}
/** 方法运行
* Method类中用于创建对象的方法
* Object invoke(Object obj, Object... args):运行方法
* 参数一:调用方法的对象
* 参数二:调用方法时,需要传入的参数(如果没有就不写)
* 返回值:被调用方法返回的值(如果没有就不写)
*/
Student student = new Student();
method.setAccessible(true);
method.invoke(student, "肯德基");// 我要吃肯德基
// 方法有返回值时,可以获取返回值
Object result = clazz.getDeclaredMethod("sleep").invoke(student);// 睡觉中~~~
System.out.println(result);// 别打扰
} catch (Exception e) {
e.printStackTrace();
}
|
上述笔记基于黑马课程