Java反射

反射是啥

反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力;
反射可以用于观察并修改程序在运行时的执行。

能干啥

反射机制主要提供了以下功能:

在运行时判断任意一个对象所属的类;

在运行时构造任意一个类的对象;

在运行时判断任意一个类所具有的成员变量和方法;

在运行时调用任意一个对象的方法;

生成动态代理。

怎么用

以下示例所有代码在gist中,点击跳转
运行结果如下:

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
通过对象获取完整包名:reflect.ATest
实例化Class类对象
aClass的父类为:java.lang.Object
---------查看每个构造方法所需参数------
参数为:java.lang.String
参数为:java.lang.String
---------通过构造方法创建实例-----------
User{name='admin', pwd='123456'}
User{name='ZHANGQIANG', pwd='######'}
---------- 获取类中所有 fields ----------
修饰符为:public
类型为:java.lang.String
修饰符为:private
类型为:java.lang.String
---------- 获取类中public fields ---------
修饰符为:public
类型为:java.lang.String
------------获取类中所有public methods ----------
public java.lang.String toString()
public java.lang.String getName()
public void setName(java.lang.String param0,)
public java.lang.String getPwd()
public void setPwd(java.lang.String param0,)
public void Methods_public()
public final void wait()
public final void wait(long param0,int param1,)
public final native void wait(long param0,)
public boolean equals(java.lang.Object param0,)
public native int hashCode()
public final native java.lang.Class getClass()
public final native void notify()
public final native void notifyAll()
------------获取类中所有methods ----------
toString
getName
setName
getPwd
Methods_private
setPwd
Methods_public
--------- 调用类中方法 ------------
Methods_public invoked
通过getMethod()调用private方法
Exception: java.lang.NoSuchMethodException
允许通过getDeclaredMethod()方法调用私有方法
Methods_private invoked
------------修改属性--------------
private final String str0 = "str0"; //私有 常量
public final String str1 = "str1"; //公有 常量
public static final String str2 = "str2"; //公有 静态 常量
private static final String str3 = "str3"; //私有 静态 常量
private String str4 = "str4"; //私有 变量
private static String str5 = "str5"; //私有 静态 变量
private User user0 = new User();
private static User user1 = new User();
private static final User user2 = new User();
str0
str1
str2
str3
************ str0/str1/str2/str3 是final类型,不可变(即便是可赋值,但最后还是输出初始值)
change_str4
change_str5
************ str4/str5 是非final类型,可改变初始值
因为user0是非static类型的对象,故会报以下错:
java.lang.IllegalArgumentException: Can not set final reflect.User field reflect.ATest.user1 to java.lang.String
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)
at java.lang.reflect.Field.get(Field.java:393)
User{name='user1', pwd='110'}
User{name='user2', pwd='110'}
---------------- 动态代理 ----------
在java中有三种类类加载器。
1.Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2.Extension ClassLoader 用来进行扩展类的加载,一般对应的是jrelibext目录中的类
3.AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
类加载器: sun.misc.Launcher$AppClassLoader
TEST
***
Process finished with exit code 0

主要代码:

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
public static void main(String[] args) {
ATest aTest = new ATest();
String packageName = aTest.getClass().getName();
System.out.println("通过对象获取完整包名:" + packageName);
try {
Class<?> aClass = Class.forName(packageName);
Class<?> bClass = new ATest().getClass();
Class<?> cClass = ATest.class;
System.out.println("实例化Class类对象");
//获取父类
Class<?> parentClass = aClass.getSuperclass();
System.out.println("aClass的父类为:" + parentClass.getName());
//获取实现的接口
Class<?>[] aClassInterfaces = aClass.getInterfaces();
for (Class<?> anInterface : aClassInterfaces) {
System.out.println("aClass实现的接口有:" + anInterface.getName());
}
/**
*
* 创建对象实例
* 1.实例化默认构造方法,调用set赋值
* 2.取得全部的构造函数 使用构造函数赋值
*
*/
Class<?> class1 = null;
class1 = Class.forName("reflect.User");
// 1. 实例化默认构造方法,调用set赋值
User user = (User) class1.newInstance();
user.setName("ZQiang94");
user.setPwd("******");
// 2.1 获取所有构造方法
Constructor<?>[] constructors = class1.getConstructors();
// 2.2 查看每个构造方法所需参数
System.out.println("\n---------查看每个构造方法所需参数------");
for (Constructor<?> constructor : constructors) {
Class<?>[] types = constructor.getParameterTypes();
for (Class<?> type : types) {
String name = type.getName();
System.out.println("参数为:" + name);
}
}
System.out.println("\n---------通过构造方法创建实例-----------");
//通过第一个构造方法创建实例
user = (User) constructors[0].newInstance();
System.out.println(user.toString());
//通过第二个构造方法创建实例
user = (User) constructors[1].newInstance("ZHANGQIANG", "######");
System.out.println(user.toString());
System.out.println("\n---------- 获取类中所有 fields ----------");
//获取类中所有属性 -- User
Field[] fields = class1.getDeclaredFields(); //getDeclaredFields
for (Field f : fields) {
int modifier = f.getModifiers(); //修饰符
System.out.println("修饰符为:" + Modifier.toString(modifier));
String name = f.getType().getName();//类型
System.out.println("类型为:" + name);
}
System.out.println("\n---------- 获取类中public fields ---------");
/**
* getFields()
Returns an array containing {@code Field} objects reflecting all
the accessible public fields of the class or interface represented by
this {@code Class} object.
*/
Field[] fields1 = class1.getFields();
if (fields1.length == 0) {
System.out.println("没有公开属性");
}
for (Field f : fields1) {
int modifier = f.getModifiers(); //修饰符
System.out.println("修饰符为:" + Modifier.toString(modifier));
String name = f.getType().getName();//类型
System.out.println("类型为:" + name);
}
System.out.println("\n------------获取类中所有public methods ----------");
Method[] methods = class1.getMethods();
for (int i = 0; i < methods.length; i++) {
StringBuilder sb = new StringBuilder("");
Method m = methods[i];
Class<?> returnType = m.getReturnType(); //返回类型
String modifiers = Modifier.toString(m.getModifiers());//修饰符
Class<?>[] types = m.getParameterTypes();//参数
sb = new StringBuilder(modifiers)
.append(" ")
.append(returnType.getName() + " ")
.append(m.getName()).append("(");
for (int j = 0; j < types.length; j++) {
String name = types[j].getName(); //参数类型
sb.append(name).append(" param" + j + ",");
}
Class<?> exce[] = methods[i].getExceptionTypes();
sb.append(")");
System.out.println(sb);
}
System.out.println("\n------------获取类中所有methods ----------");
Method[] declaredMethods = class1.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getName());
}
System.out.println("\n--------- 调用类中方法 ------------");
// 调用public方法
Method method1 = class1.getMethod("Methods_public");
method1.invoke(class1.newInstance());
/**
* 调用private方法
* Exception: java.lang.NoSuchMethodException
*
* Method method2 = class1.getMethod("Methods_private");
* method2.invoke(class1.newInstance());
*/
System.out.println("通过getMethod()调用private方法\n" +
"Exception: java.lang.NoSuchMethodException");
System.out.println("允许通过getDeclaredMethod()方法调用私有方法");
Method method2 = class1.getDeclaredMethod("Methods_private");
method2.setAccessible(true);
method2.invoke(class1.newInstance());
System.out.println("\n------------修改属性--------------");
Field[] fs = ATest.class.getDeclaredFields();
System.out.println("private final String str0 = \"str0\"; //私有 常量\n" +
"public final String str1 = \"str1\"; //公有 常量\n" +
"public static final String str2 = \"str2\"; //公有 静态 常量\n" +
"private static final String str3 = \"str3\"; //私有 静态 常量\n" +
"private String str4 = \"str4\"; //私有 变量\n" +
"private static String str5 = \"str5\"; //私有 静态 变量\n" +
"private User user0 = new User();\n" +
"private static User user1 = new User();\n" +
"private static final User user2 = new User();");
for (Field f : fs) {
f.setAccessible(true);
switch (f.getName()) {
case "str0":
f.set(aTest, "change_str0");
System.out.println(aTest.getStr0());
break;
case "str1":
f.set(aTest, "change_str1");
System.out.println(aTest.getStr1());
break;
case "str2":
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.set(f, f.getModifiers() & ~Modifier.FINAL);
f.set(null, "change_str2");
System.out.println(aTest.getStr2());
break;
case "str3":
Field modifiersField1 = Field.class.getDeclaredField("modifiers");
modifiersField1.setAccessible(true);
modifiersField1.set(f, f.getModifiers() & ~Modifier.FINAL);
f.set(aTest, "change_str3");
System.out.println(aTest.getStr3());
System.out.println("************ str0/str1/str2/str3 是final类型,不可变(即便是可赋值,但最后还是输出初始值)");
break;
case "str4":
f.set(aTest, "change_str4");
System.out.println(aTest.getStr4());
break;
case "str5":
f.set(aTest, "change_str5");
System.out.println(aTest.getStr5());
System.out.println("************ str4/str5 是非final类型,可改变初始值");
break;
case "user0":
/*User u = (User) f.get("user0");
u.setName("user0");
u.setPwd("110");
System.out.println(aTest.getUser0().toString());*/
System.out.println("因为user0是非static类型的对象,故会报以下错:" +
"\njava.lang.IllegalArgumentException: Can not set final reflect.User field reflect.ATest.user1 to java.lang.String\n" +
"\tat sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)\n" +
"\tat sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)\n" +
"\tat sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)\n" +
"\tat sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)\n" +
"\tat java.lang.reflect.Field.get(Field.java:393)");
break;
case "user1":
User u1 = (User) f.get("user1");
u1.setName("user1");
u1.setPwd("110");
System.out.println(aTest.getUser1().toString());
break;
case "user2":
User u2 = (User) f.get("user2");
u2.setName("user2");
u2.setPwd("110");
System.out.println(aTest.getUser2());
break;
default:
break;
}
}
System.out.println("\n---------------- 动态代理 ----------");
System.out.println("在java中有三种类类加载器。\n" +
"\n" +
"1.Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。\n" +
"\n" +
"2.Extension ClassLoader 用来进行扩展类的加载,一般对应的是jrelibext目录中的类\n" +
"\n" +
"3.AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。\n" +
"如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。\n");
System.out.println("类加载器: " + aTest.getClass().getClassLoader().getClass().getName());
MyInvocationHandler handler = new MyInvocationHandler();
Subject sub = (Subject) handler.bind(new SubjectImpl());
String info = sub.outInfo("TEST", "***");
System.out.println(info);
} catch (Exception e) {
e.printStackTrace();
}
}

示例
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
public class Test {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
Method method = list.getClass().getMethod("add", Object.class);
method.invoke(list, "String");
list.add(100000000);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
int[] arr = {1, 2, 3, 4, 5};
System.out.println("数组内容为:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
Class<?> type = arr.getClass().getComponentType();
System.out.println("数组类型为:" + type.getName());
for (int i = 0; i < arr.length; i++) {
Array.set(arr, i, -1);
}
System.out.println("修改后的数组为:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
//-----------修改数组长度
System.out.println("将数组长度为3的数组变为8");
String[] atr = {"a", "b", "c"};
String[] str1 = (String[]) arrayInc(atr, 8);
print(str1);
}
// 修改数组大小
public static Object arrayInc(Object obj, int len) {
Class<?> arr = obj.getClass().getComponentType();
Object newArr = Array.newInstance(arr, len);
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArr, 0, co);
return newArr;
}
// 打印
public static void print(Object obj) {
Class<?> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("数组长度为: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
System.out.println();
}
}

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
String
100000000
数组内容为:
1
2
3
4
5
数组类型为:int
修改后的数组为:
-1
-1
-1
-1
-1
将数组长度为3的数组变为8
数组长度为: 8
a b c null null null null null
Process finished with exit code 0

利弊

利:与Java动态编辑相结合,在运行时动态获取类的实例,提高系统的灵活性和拓展性
弊:编译器没法对反射相关的代码做优化

参考链接

编程百科
Java反射慢在哪里?
示例代码

Fork me on GitHub