前言
相信很多人都知道反射可以說是Java中最強大的技術(shù)了,它可以做的事情太多太多,很多優(yōu)秀的開源框架都是通過反射完成的,比如最初的很多注解框架,后來因為java反射影響性能,所以被運行時注解APT替代了,java反射有個開源框架jOOR相信很多人都用過,不過我們還是要學(xué)習(xí)反射的基礎(chǔ)語法,這樣才能自己寫出優(yōu)秀的框架,當(dāng)然這里所講的反射技術(shù),是學(xué)習(xí)Android插件化技術(shù)、Hook技術(shù)等必不可少的!
一、基本反射技術(shù)
1.1 根據(jù)一個字符串得到一個類
getClass方法
1
2
3
|
String name = "Huanglinqing" ; Class c1 = name.getClass(); System.out.println(c1.getName()); |
打印結(jié)果如下:
Class.forName
比如我們獲取java.lang.String的類名
1
2
3
4
5
6
7
|
String name = "java.lang.String" ; Class c1 = null ; try { c1 = Class.forName(name); System.out.println(c1.getName()); } catch (ClassNotFoundException e) { } |
這里也通過捕獲異常,因為我們傳的這個字符串可能不合法,字符串合法命名是類的命名空間和類的名稱組成
打印結(jié)果如下:
我們還可以通過c1.getSuperclass()獲取到他的父類
Type屬性
基本類型都有type屬性,可以得到這個基本類型的類型,比如:
1
2
3
4
|
Class c1 = Boolean.TYPE; Class c2 = Byte.TYPE; Class c3 = Float.TYPE; Class c4 = Double.TYPE; |
停停停!這些東西有啥子用,如此雞肋! 別急,一切都是為后續(xù)做準(zhǔn)備。
二、獲取類的成員
當(dāng)類中方法定義為私有的時候我們能調(diào)用?不能!當(dāng)變量是私有的時候我們能獲取嗎?不能!但是反射可以,比如源碼中有你需要用到的方法,但是那個方法是私有的,這個時候你就可以通過反射去執(zhí)行這個私有方法,并且獲取私有變量。
獲取類的構(gòu)造函數(shù)
為了便于測試,我們定義一個Test類,Test類如下:(省略get和set方法)
Test類中我們定義是三個私有變量,生成兩個公有的含參構(gòu)造方法和一個私有的含參構(gòu)造方法以及一個公有的無參構(gòu)造方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class Test { private int age; private String name; private int testint; public Test( int age) { this .age = age; } public Test( int age, String name) { this .age = age; this .name = name; } private Test(String name) { this .name = name; } public Test() { } |
下面我們通過反射獲取這些構(gòu)造方法
獲取類的所有構(gòu)造方法
1
2
3
4
|
Test test = new Test(); Class c4 = test.getClass(); Constructor[] constructors ; constructors = c4.getDeclaredConstructors(); |
通過getDeclaredConstructors可以返回類的所有構(gòu)造方法,返回的是一個數(shù)組因為構(gòu)造方法可能不止一個,通過getModifiers可以得到構(gòu)造方法的類型,getParameterTypes可以得到構(gòu)造方法的所有參數(shù),返回的是一個Class數(shù)組,所以我們?nèi)绻氆@取所有構(gòu)造方法以及每個構(gòu)造方法的參數(shù)類型,可以有如下代碼:
1
2
3
4
5
6
7
8
|
for ( int i = 0 ; i < constructors.length; i++) { System.out.print(Modifier.toString(constructors[i].getModifiers()) + "參數(shù):" ); Class[] parametertypes = constructors[i].getParameterTypes(); for ( int j = 0 ; j < parametertypes.length; j++) { System.out.print(parametertypes[j].getName() + " " ); } System.out.println( "" ); } |
運行結(jié)果如下所示:
這樣我們就得到了類中所有構(gòu)造方法和構(gòu)造方法中的參數(shù),那么我們?nèi)绾潍@取特定的構(gòu)造方法呢?
獲取類中特定的構(gòu)造方法
我們可以通過getConstructors方法獲取類中 所有的public類型的構(gòu)造方法,代碼和上面一樣就不演示了。
我們可以通過getDeclaredConstructor()方法傳參獲取特定參數(shù)類型的構(gòu)造方法,這里注意是getDeclaredConstructor()不是 getDeclaredConstructors() ,所以返回的是一個Class對象而不是一個Class數(shù)組。
獲取無參構(gòu)造方法直接不傳參數(shù),如下所示:
1
2
3
4
5
6
|
try { constructors = c4.getDeclaredConstructor(); System.out.print(Modifier.toString(constructors.getModifiers()) + ); } catch (NoSuchMethodException e) { e.printStackTrace(); } |
這里要進行異常捕獲,因為可能不存在對應(yīng)的構(gòu)造方法,打印結(jié)果如下:
如果我們想獲取有兩個參數(shù)分別為int和String類型的構(gòu)造方法,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
|
Class[] p = { int . class ,String. class }; try { constructors = c4.getDeclaredConstructor(p); System.out.print(Modifier.toString(constructors.getModifiers()) + "參數(shù):" ); Class[] parametertypes = constructors.getParameterTypes(); for ( int j = 0 ; j < parametertypes.length; j++) { System.out.print(parametertypes[j].getName() + " " ); } } catch (NoSuchMethodException e) { e.printStackTrace(); } |
這里我們同樣打印出構(gòu)造方法的參數(shù):
調(diào)用構(gòu)造方法
從這里開始慢慢到了關(guān)鍵的一步,得到類的實例,我們主要借助于newInstance方法,為了方便演示我們將測試類的兩個構(gòu)造方法打印出來.
1
2
3
4
5
6
7
8
9
10
11
12
|
public Test( int age, String name) { this .age = age; this .name = name; System.out.println( "hello" + name + "i am" + age); } private Test(String name) { this .name = name; System.out.println( "My Name is" + name); } |
我們先來調(diào)用public的方法,如下所示:
1
2
3
|
Class[] p = { int . class ,String. class }; constructors = c4.getDeclaredConstructor(p); constructors.newInstance( 24 , "HuangLinqing" ); |
運行打印結(jié)果如下:
那么調(diào)用私有構(gòu)造方法呢,和上面一樣,只是我們要設(shè)置constructors.setAccessible(true);代碼如下:
1
2
3
4
|
Class[] p = {String. class }; constructors = c4.getDeclaredConstructor(p); constructors.setAccessible( true ); constructors.newInstance( "HuangLinqing" ); |
打印結(jié)果如下:
調(diào)用類的私有方法
如何調(diào)用類中的私有方法呢,我們先在測試類中編寫一個測試的私有方法 如下:
1
2
3
|
private void welcome(String tips){ System.out.println(tips); } |
我們知道如果我們要正常的調(diào)用類的方法都是通過類.方法調(diào)用,所以我們調(diào)用私有方法也需要得到類的實例,而我們上面newInstace已經(jīng)得到了類的實例,這樣就好辦了。
1
2
3
|
Class[] p4 = {String. class }; Method method = c4.getDeclaredMethod( "welcome" ,p4); method.setAccessible( true ); |
我們首先通過 getDeclaredMethod方法獲取到這個私有方法,第一個參數(shù)是方法名,第二個參數(shù)是參數(shù)類型
然后通過invoke方法執(zhí)行,invoke需要兩個參數(shù)一個是類的實例,一個是方法參數(shù)。
1
2
3
4
5
|
Class[] p4 = {String. class }; Method method = c4.getDeclaredMethod( "welcome" ,p4); method.setAccessible( true ); Object arg1s[] = { "歡迎關(guān)注代碼男人技術(shù)公眾號" }; method.invoke(test,arg1s); |
test類的實例當(dāng)不能new 獲取的時候我們也可以通過反射獲取,就是上面的newInstance方法。打印結(jié)果如下:
獲取類的私有字段并修改值
看到這里你可能會說,有了set方法,什么私有不私有,test.set不就可以了,但是這里要注意我們是沒有辦法得到這個類的實例的,要不然都可以得到實例就沒有反射一說了。我們在通過反射得到類的實例之后先獲取字段:
1
2
3
|
Field field = c4.getDeclaredField( "name" ); field.setAccessible( true ); field.set(o, "代碼男人" ); |
o是我們上面通過反射構(gòu)造方法獲取的實例, 打印field.get(o).toString()的值如下:
不過要注意的是我們修改了name的值只對當(dāng)前的實例對象有效。
Java的基本反射語法就是這樣了,歡迎加入技術(shù)群一起探討!
最后反射封裝類如下:
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
|
package jnidemo.hlq.com.hookdemo; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author Huanglinqing * @date 2019/4/28 */ public class Reflex { /** * 獲取無參構(gòu)造函數(shù) * @param className * @return */ public static Object createObject(String className) { Class[] pareTyples = new Class[]{}; Object[] pareVaules = new Object[]{}; try { Class r = Class.forName(className); return createObject(r, pareTyples, pareVaules); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } /** * 獲取無參構(gòu)造方法 * @param clazz * @return */ public static Object createObject(Class clazz) { Class[] pareTyple = new Class[]{}; Object[] pareVaules = new Object[]{}; return createObject(clazz, pareTyple, pareVaules); } /** * 獲取一個參數(shù)的構(gòu)造函數(shù) 已知className * * @param className * @param pareTyple * @param pareVaule * @return */ public static Object createObject(String className, Class pareTyple, Object pareVaule) { Class[] pareTyples = new Class[]{pareTyple}; Object[] pareVaules = new Object[]{pareVaule}; try { Class r = Class.forName(className); return createObject(r, pareTyples, pareVaules); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } /** * 獲取單個參數(shù)的構(gòu)造方法 已知類 * * @param clazz * @param pareTyple * @param pareVaule * @return */ public static Object createObject(Class clazz, Class pareTyple, Object pareVaule) { Class[] pareTyples = new Class[]{pareTyple}; Object[] pareVaules = new Object[]{pareVaule}; return createObject(clazz, pareTyples, pareVaules); } /** * 獲取多個參數(shù)的構(gòu)造方法 已知className * @param className * @param pareTyples * @param pareVaules * @return */ public static Object createObject(String className, Class[] pareTyples, Object[] pareVaules) { try { Class r = Class.forName(className); return createObject(r, pareTyples, pareVaules); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } /** * 獲取構(gòu)造方法 * * @param clazz * @param pareTyples * @param pareVaules * @return */ public static Object createObject(Class clazz, Class[] pareTyples, Object[] pareVaules) { try { Constructor ctor = clazz.getDeclaredConstructor(pareTyples); ctor.setAccessible( true ); return ctor.newInstance(pareVaules); } catch (Exception e) { e.printStackTrace(); } return null ; } /** * 獲取多個參數(shù)的方法 * @param obj * @param methodName * @param pareTyples * @param pareVaules * @return */ public static Object invokeInstanceMethod(Object obj, String methodName, Class[] pareTyples, Object[] pareVaules) { if (obj == null ) { return null ; } try { //調(diào)用一個private方法 //在指定類中獲取指定的方法 Method method = obj.getClass().getDeclaredMethod(methodName, pareTyples); method.setAccessible( true ); return method.invoke(obj, pareVaules); } catch (Exception e) { e.printStackTrace(); } return null ; } /** * 獲取一個參數(shù)的方法 * @param obj * @param methodName * @param pareTyple * @param pareVaule * @return */ public static Object invokeInstanceMethod(Object obj, String methodName, Class pareTyple, Object pareVaule) { Class[] pareTyples = {pareTyple}; Object[] pareVaules = {pareVaule}; return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules); } /** * 獲取無參方法 * @param obj * @param methodName * @return */ public static Object invokeInstanceMethod(Object obj, String methodName) { Class[] pareTyples = new Class[]{}; Object[] pareVaules = new Object[]{}; return invokeInstanceMethod(obj, methodName, pareTyples, pareVaules); } /** * 無參靜態(tài)方法 * @param className * @param method_name * @return */ public static Object invokeStaticMethod(String className, String method_name) { Class[] pareTyples = new Class[]{}; Object[] pareVaules = new Object[]{}; return invokeStaticMethod(className, method_name, pareTyples, pareVaules); } /** * 獲取一個參數(shù)的靜態(tài)方法 * @param className * @param method_name * @param pareTyple * @param pareVaule * @return */ public static Object invokeStaticMethod(String className, String method_name, Class pareTyple, Object pareVaule) { Class[] pareTyples = new Class[]{pareTyple}; Object[] pareVaules = new Object[]{pareVaule}; return invokeStaticMethod(className, method_name, pareTyples, pareVaules); } /** * 獲取多個參數(shù)的靜態(tài)方法 * @param className * @param method_name * @param pareTyples * @param pareVaules * @return */ public static Object invokeStaticMethod(String className, String method_name, Class[] pareTyples, Object[] pareVaules) { try { Class obj_class = Class.forName(className); return invokeStaticMethod(obj_class, method_name, pareTyples, pareVaules); } catch (Exception e) { e.printStackTrace(); } return null ; } /** * 無參靜態(tài)方法 * @param method_name * @return */ public static Object invokeStaticMethod(Class clazz, String method_name) { Class[] pareTyples = new Class[]{}; Object[] pareVaules = new Object[]{}; return invokeStaticMethod(clazz, method_name, pareTyples, pareVaules); } /** * 一個參數(shù)靜態(tài)方法 * @param clazz * @param method_name * @param classType * @param pareVaule * @return */ public static Object invokeStaticMethod(Class clazz, String method_name, Class classType, Object pareVaule) { Class[] classTypes = new Class[]{classType}; Object[] pareVaules = new Object[]{pareVaule}; return invokeStaticMethod(clazz, method_name, classTypes, pareVaules); } /** * 多個參數(shù)的靜態(tài)方法 * @param clazz * @param method_name * @param pareTyples * @param pareVaules * @return */ public static Object invokeStaticMethod(Class clazz, String method_name, Class[] pareTyples, Object[] pareVaules) { try { Method method = clazz.getDeclaredMethod(method_name, pareTyples); method.setAccessible( true ); return method.invoke( null , pareVaules); } catch (Exception e) { e.printStackTrace(); } return null ; } public static Object getFieldObject(String className, Object obj, String filedName) { try { Class obj_class = Class.forName(className); return getFieldObject(obj_class, obj, filedName); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null ; } public static Object getFieldObject(Class clazz, Object obj, String filedName) { try { Field field = clazz.getDeclaredField(filedName); field.setAccessible( true ); return field.get(obj); } catch (Exception e) { e.printStackTrace(); } return null ; } public static void setFieldObject(Class clazz, Object obj, String filedName, Object filedVaule) { try { Field field = clazz.getDeclaredField(filedName); field.setAccessible( true ); field.set(obj, filedVaule); } catch (Exception e) { e.printStackTrace(); } } public static void setFieldObject(String className, Object obj, String filedName, Object filedVaule) { try { Class obj_class = Class.forName(className); setFieldObject(obj_class, obj, filedName, filedVaule); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Object getStaticFieldObject(String className, String filedName) { return getFieldObject(className, null , filedName); } public static Object getStaticFieldObject(Class clazz, String filedName) { return getFieldObject(clazz, null , filedName); } public static void setStaticFieldObject(String classname, String filedName, Object filedVaule) { setFieldObject(classname, null , filedName, filedVaule); } public static void setStaticFieldObject(Class clazz, String filedName, Object filedVaule) { setFieldObject(clazz, null , filedName, filedVaule); } } |
到此這篇關(guān)于Java反射技術(shù)詳解及實例解析的文章就介紹到這了,更多相關(guān)Java反射技術(shù)示例詳解內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/huangliniqng/article/details/88554510