Java 基础 - 反射
# 什么是反射
当虚拟机加载完类信息之后,就会在堆内存的方法区中针对每个类产生唯一一个 Class 类型的对象,该对象包含了其它类的结构信息。正常来说可以通过 new 的方式去创建一个类的对象,但是也可以通过记录类完整信息的 Class 对象去反向分析类的结构,这种能够分析类的结构和能力的程序称为反射(reflective),是一种功能强大且复杂的机制。反射机制可以用来:
- 在运行时分析类的成员变量和方法;
- 在运行时调用一个对象的成员变量和方法;
- 在运行时构造一个类的对象;
- 在运行时获取一个对象的类信息;
- 在运行时检查对象。
反射机制主要应用在开发工具(如框架)方面,在应用开发中使用较少。
# 核心类库
和反射相关的有 4 个核心类:
java.lang.Class
:用以表示类信息。java.lang.reflect.Constructor
:用以表示类的构造器。java.lang.reflect.Field
:用以表示类的成员变量。java.lang.reflect.Method
:用以表示类的方法。
# Class 类
java.lang.Class 类是一个特殊的类(实际上是一个泛型类),它在程序运行期间始终为所有对象维护一个运行时的类型标识,其中记录了各个类的完整结构信息,包括构造器、成员变量和方法的属性及结果。Class 类是反射的根源,任何想通过反射动态加载、运行的行为都必须从 Class 对象开始。
Class 类的主要方法:
static Class forName(String name)
:返回指定类名 name 的 Class 对象。Object newInstance()
:调用缺省构造函数,返回该 Class 对象的一个实例。String getName()
:返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。Class getSuperClass()
:返回当前 Class 对象的父类的 Class 对象。Class[] getInterfaces()
:返回当前 Class 对象的所有接口。ClassLoader getClassLoader()
:返回该类的类加载器。Constructor<T>[] getConstructors()
:返回此 Class 对象所表示的类的所有 public 构造方法。Constructor<T>[] getDeclaredConstructors()
:返回此 Class 对象表示的类声明的所有构造方法。Field[] getFields()
:返回此 Class 对象所表示的类或接口的 public 的 Field。Field[] getDeclaredFields()
:返回此 Class 对象所表示的类或接口的全部 Field。Method getMethod()
:返回此 Class 对象所表示的类或接口的 public 的方法。Method[] getDeclaredMethods()
:返回此 Class 对象所表示的类或接口的全部方法。
获取 Class 对象的三种方式:
- 通过对象的
getClasss()
方法
Student s;
Class clazz = s.getClass();
1
2
3
2
3
- 使用 Class 类的静态方法
forName()
Class clazz = Class.forName("com.sqlboy.Student");
1
- 通过
T.class
获取
Class clazz = Student.class;
1
提示
由于虚拟机为每个类型都管理了一个唯一的 Class 对象,所以在比较两个类是否相等时可以使用==。
if (Student.class == Class.forName("com.sqlboy.Student")){
// pass
}
1
2
3
2
3
# Constructor 类
Constructor 类用以描述类的构造器信息。主要方法:
int getModifiers()
:获取构造器的修饰符。String getName()
:获取方法名称。Class<?>[] getParameterTypes()
:获取参数类型。
# Field 类
Field 类用以描述类的成员变量信息。主要方法:
Field[] getFields()
:获取 Class 对象表示的类或接口的 pubic 的 Field。Field[] getDeclaredFields()
:获取 Class 对象所表示的类或接口的全部 Field。
# Method 类
Method 类用以描述类的方法信息。主要方法:
Class<?> getReturnType()
:获取返回值类型。Class<?>[] getParameterTypes()
:获取所有参数。int getModifiers()
:获取修饰符。Class<?>[] getExceptionTypes()
获取异常信息。Object invoke(Object obj, Object... args)
:执行类对象的方法。
对于 invoke 方法的使用说明:
- invoke 方法的返回值 Object 对应原方法的返回值,若原方法无返回值,则 Object 为 null。
- 若原方法为静态方法,此时形参 obj 为 null。
- 若原方法形参列表为空,则形参 args 为 null。
- 若原方法声明为 private,则需要在调用 invoke 方法前显式调用方法对象的 setAccessible(true) 方法。
示例:
package com.sqlboy.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* 在运行时创建类对象
*/
public class ClassTest {
public static void main(String[] args) throws Exception {
System.out.println("程序已经开始执行");
Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
Object person = constructor.newInstance("张三", 18);
System.out.println(person);
Method say = clazz.getDeclaredMethod("say");
say.setAccessible(true);
say.invoke(person);
}
}
class Person {
private String name;
private Integer age;
Person() {
}
Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String toString() {
return "name: " + name + ",age: " + age;
}
private void say() {
System.out.println("我的名字是:" + name + ", 我今年 " + 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
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
输出:
程序已经开始执行
name: 张三,age: 18
我的名字是:张三, 我今年 18 岁
1
2
3
2
3
# 综合案例
下面的代码是一个关于反射的综合应用,输入任意类,将会打印该类的全部信息:
import java.lang.reflect.*;
import java.util.*;
public class ReflectionTest {
public static void main(String[] args) {
// 从命令行参数或用户输入读取类名
String name;
if (args.length > 0) name = args[0];
else {
Scanner in = new Scanner(System.in);
System.out.println("Enter a class name (e.g. java.util.Date): ");
name = in.next();
}
try{
//打印类名和父类名(if != Object)
Class cl = Class.forName(name);
Class supercl = cl.getSuperclass();
String modifiers = Modifier.toString(cl.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print("class " + name);
if (supercl != null && supercl != Object.class ){
System.out.print(" extends " + supercl.getName());
}
System.out.print("\n{\n");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.exit(0);
}
/**
* 打印类的所有构造函数
* @param cl
*/
public static void printConstructors(Class cl) {
Constructor[] constructors = cl.getConstructors();
for (Constructor c : constructors){
String name = c.getName();
System.out.print(" ");
String modifiers = Modifier.toString(cl.getModifiers());//修饰符字符串
if (modifiers.length() > 0){
System.out.print(modifiers + " ");
}
System.out.print(name + "(");
//打印参数类型
Class[] parameterType = c.getParameterTypes();
for (int j = 0; j < parameterType.length; j++) {
if (j > 0) System.out.print(", ");
System.out.print(parameterType[j].getName());
}
System.out.println(");");
}
}
/**
* 打印一个类的所有方法
* @param cl
*/
public static void printMethods(Class cl) {
Method[] methods = cl.getDeclaredMethods();
for (Method m : methods){
Class returnType = m.getReturnType();
String name = m.getName();
System.out.print(" ");
//打印修饰符,返回类型,以及方法名
String modifiers = Modifier.toString(cl.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.print(returnType.getName() + " " + name + "(");
//打印参数类型
Class[] parameterTypes = m.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
if (j > 0) System.out.print(", ");
System.out.print(parameterTypes[j].getName());
}
System.out.println(");");
}
}
/**
* 打印类的所有字段
* @param cl
*/
public static void printFields(Class cl) {
Field[] declaredFields = cl.getDeclaredFields();
for (Field f : declaredFields){
Class type = f.getType();
String name = f.getName();
System.out.print(" ");
//打印 修饰符 类型名 变量名
String modifiers = Modifier.toString(f.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers + " ");
System.out.println(type.getName() + " " + 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
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
使用示例:
$ javac ReflectionTest.java
$ java ReflectionTest
Enter a class name (e.g. java.util.Date):
java.lang.String
public final class java.lang.String
{
public final java.lang.String([B, int, int);
public final java.lang.String([B, java.nio.charset.Charset);
public final java.lang.String([B, java.lang.String);
public final java.lang.String([B, int, int, java.nio.charset.Charset);
public final java.lang.String([B, int, int, java.lang.String);
public final java.lang.String(java.lang.StringBuilder);
public final java.lang.String(java.lang.StringBuffer);
public final java.lang.String([B);
public final java.lang.String([I, int, int);
public final java.lang.String();
public final java.lang.String([C);
public final java.lang.String(java.lang.String);
public final java.lang.String([C, int, int);
public final java.lang.String([B, int);
public final java.lang.String([B, int, int, int);
public final boolean equals(java.lang.Object);
public final java.lang.String toString();
public final int hashCode();
public final int compareTo(java.lang.Object);
public final int compareTo(java.lang.String);
public final int indexOf(java.lang.String, int);
public final int indexOf([C, int, int, java.lang.String, int);
public final int indexOf([C, int, int, [C, int, int, int);
public final int indexOf(int);
public final int indexOf(java.lang.String);
public final int indexOf(int, int);
public final java.lang.String valueOf(char);
public final java.lang.String valueOf(java.lang.Object);
public final java.lang.String valueOf(boolean);
public final java.lang.String valueOf([C, int, int);
public final java.lang.String valueOf([C);
public final java.lang.String valueOf(double);
public final java.lang.String valueOf(float);
public final java.lang.String valueOf(long);
public final java.lang.String valueOf(int);
public final void checkBounds([B, int, int);
public final int length();
public final boolean isEmpty();
public final char charAt(int);
public final int codePointAt(int);
public final int codePointBefore(int);
public final int codePointCount(int, int);
public final int offsetByCodePoints(int, int);
public final void getChars(int, int, [C, int);
public final void getChars([C, int);
public final [B getBytes();
public final [B getBytes(java.lang.String);
public final void getBytes(int, int, [B, int);
public final [B getBytes(java.nio.charset.Charset);
public final boolean contentEquals(java.lang.StringBuffer);
public final boolean contentEquals(java.lang.CharSequence);
public final boolean nonSyncContentEquals(java.lang.AbstractStringBuilder);
public final boolean equalsIgnoreCase(java.lang.String);
public final int compareToIgnoreCase(java.lang.String);
public final boolean regionMatches(int, java.lang.String, int, int);
public final boolean regionMatches(boolean, int, java.lang.String, int, int);
public final boolean startsWith(java.lang.String);
public final boolean startsWith(java.lang.String, int);
public final boolean endsWith(java.lang.String);
public final int indexOfSupplementary(int, int);
public final int lastIndexOf(int, int);
public final int lastIndexOf([C, int, int, [C, int, int, int);
public final int lastIndexOf([C, int, int, java.lang.String, int);
public final int lastIndexOf(java.lang.String, int);
public final int lastIndexOf(int);
public final int lastIndexOf(java.lang.String);
public final int lastIndexOfSupplementary(int, int);
public final java.lang.String substring(int);
public final java.lang.String substring(int, int);
public final java.lang.CharSequence subSequence(int, int);
public final java.lang.String concat(java.lang.String);
public final java.lang.String replace(char, char);
public final java.lang.String replace(java.lang.CharSequence, java.lang.CharSequence);
public final boolean matches(java.lang.String);
public final boolean contains(java.lang.CharSequence);
public final java.lang.String replaceFirst(java.lang.String, java.lang.String);
public final java.lang.String replaceAll(java.lang.String, java.lang.String);
public final [Ljava.lang.String; split(java.lang.String, int);
public final [Ljava.lang.String; split(java.lang.String);
public final java.lang.String join(java.lang.CharSequence, [Ljava.lang.CharSequence;);
public final java.lang.String join(java.lang.CharSequence, java.lang.Iterable);
public final java.lang.String toLowerCase(java.util.Locale);
public final java.lang.String toLowerCase();
public final java.lang.String toUpperCase();
public final java.lang.String toUpperCase(java.util.Locale);
public final java.lang.String trim();
public final [C toCharArray();
public final java.lang.String format(java.util.Locale, java.lang.String, [Ljava.lang.Object;);
public final java.lang.String format(java.lang.String, [Ljava.lang.Object;);
public final java.lang.String copyValueOf([C, int, int);
public final java.lang.String copyValueOf([C);
public final java.lang.String intern();
private final [C value;
private int hash;
private static final long serialVersionUID;
private static final [Ljava.io.ObjectStreamField; serialPersistentFields;
public static final java.util.Comparator CASE_INSENSITIVE_ORDER;
}
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
上次更新: 2023/11/01, 03:11:44