閱讀目錄
Java反射API
Java反射指的是在運行狀態時,能夠獲取類的屬性和方法或者修改類運行時行為的過程。
java.lang.Class類提供了很多方法用于獲取元數據、檢查和改變類運行時的行為。
Java的反射主要涉及java.lang和java.lang.reflect包下的類。
反射應用場景舉例
- IDE, 如Eclipse、MyEclipse、NetBeans等;
- 調試器;
- 測試工具等;
- 各大框架、spring、hibernate等;
java.lang.Class類
java.lang.Class主要提供了以下兩個功能:
- 提供方法用于訪問運行期間類的元數據;
- 提供方法用于檢查和修改類的運行時行為;
java.lang.Class類常用方法
Method | Description |
---|---|
1) public String getName() | 返回類名 |
2) public static Class forName(String className)throws ClassNotFoundException | 加載類并返回Class對象 |
3) public Object newInstance()throws InstantiationException,IllegalAccessException | 創建實例對象 |
4) public boolean isInterface() | 判斷是否是接口 |
5) public boolean isArray() | 判斷是否是數組 |
6) public boolean isPrimitive() | 判斷是否是原始數據類型 |
7) public Class getSuperclass() | 返回父類Class引用 |
8) public Field[] getDeclaredFields()throws SecurityException | 返回類的成員屬性字段數組 |
9) public Method[] getDeclaredMethods()throws SecurityException | 返回類的方法數組 |
10) public Constructor[] getDeclaredConstructors()throws SecurityException | 返回類的構造方法數組 |
11) public Method getDeclaredMethod(String name,Class[] parameterTypes)throws NoSuchMethodException,SecurityException | 返回類中指定參數類型的方法 |
怎樣獲取Class對象
有三種方式,如下:
- Class類的forName()方法,動態加載,運行時,開始裝入類, 并做類的靜態初始化
- 對象的getClass()方法,靜態加載(編譯時已加載)
- .class語法, 靜態加載(編譯時已加載)
forName()方法示例
可用于動態加載,當你知道類的全限定名時,可以使用該方式。注意原始數據類型不適用該方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package tmp; class Simple { } public class Test { public static void main(String args[]) throws ClassNotFoundException { Class<?> c = Class.forName( "tmp.Simple" ); System.out.println(c.getName()); System.out.println(c.getSimpleName()); } } |
1
2
|
tmp.Simple Simple |
getClass()方法示例:
從實例對象中獲取Class對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package tmp; class Simple { } public class Test { void printName(Object obj) { } public static void main(String args[]) { Simple s = new Simple(); Class<? extends Object> c = s.getClass(); System.out.println(c.getName()); System.out.println(c.getSimpleName()); } } |
1
2
|
tmp.Simple Simple |
.class語法示例
作用于類名上,也可應用于原始數據類型,如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
package tmp; public class Test { public static void main(String args[]) { Class<Boolean> c = boolean . class ; System.out.println(c.getName()); Class<Test> c2 = Test. class ; System.out.println(c2.getName()); } } |
1
2
|
boolean tmp.Test |
判斷Class對象對應的類型
以下方法可用于判斷Class對象對應的類型:
1) public boolean isInterface(): 是否對應接口 |
2) public boolean isArray(): 是否對應數組 |
3) public boolean isPrimitive(): 是否對應原始數據類型 |
代碼示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package tmp; class Simple { } interface My { } public class Test { public static void main(String args[]) { try { Class<?> c = Class.forName( "tmp.Simple" ); System.out.println(c.isInterface()); Class<?> c2 = Class.forName( "tmp.My" ); System.out.println(c2.isInterface()); } catch (Exception e) { System.out.println(e); } } } |
1
2
|
false true |
通過反射創建實例對象
有兩種方式,如下:
- 通過Class對象的newInstance()方法創建,這種方式只能調用無參構造方法;
- 通過Constructor對象的newInstance()方法創建,這種方式適用于有參構造方法,并且還可以破壞單例模式,調用私有構造方法;
所以,通常來講,第二種方式比第一種使用范圍更廣。
Class對象調用newInstance()方法示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package tmp; class Simple { void message() { System.out.println( "Hello Java" ); } } public class Test { public static void main(String args[]) { try { Class<?> c = Class.forName( "tmp.Simple" ); Simple s = (Simple) c.newInstance(); s.message(); } catch (Exception e) { System.out.println(e); } } } |
Hello Java
Constructor對象調用newInstance()方法示例
注意這里可以根據傳入參數的類型來得到指定的構造方法,還可以改變構造方法的訪問權限限制。
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
|
package tmp; import java.lang.reflect.Constructor; class Simple { private String msg; void message() { System.out.println( "Hello Java," + msg); } private Simple(String s){ this .msg = s; } } public class Test { public static void main(String args[]) { try { Class<?> c = Class.forName( "tmp.Simple" ); Constructor<?> con = c.getDeclaredConstructor(String. class ); con.setAccessible( true ); Simple s = (Simple) con.newInstance( "..." ); s.message(); } catch (Exception e) { System.out.println(e); } } } |
Hello Java,...
通過反射調用私有方法
通過反射,我們可以調用其它類的私有方法,主要涉及java.lang.Class和java.lang.reflect.Method類;
其中主要是用到了Method類的setAccessible方法和invoke方法,前者修改訪問權限,后者調用方法。
通過調用有參私有方法示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package tmp; import java.lang.reflect.Method; class A { private void cube( int n) { System.out.println(n * n * n); } } class Test { public static void main(String args[]) throws Exception { Class<A> c = A. class ; Object obj = c.newInstance(); Method m = c.getDeclaredMethod( "cube" , new Class[]{ int . class }); m.setAccessible( true ); m.invoke(obj, 4 ); } } |
關于javap工具
使用javap命令可以反匯編java的字節碼文件,展示class文件中的字段屬性、構造方法、普通方法信息;
使用說明:
javap java.lang.Object示例
javap -c Test示例:
寫個簡單的Test類,如下:
1
2
3
4
5
6
7
8
9
10
11
|
package tmp; class Simple { } public class Test { public static void main(String args[]) { System.out.println( "Hello" ); } } |
輸入javap -c Test:
參考資料
基本屬于翻譯,做了小部分修改
http://www.javatpoint.com/java-reflection
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持服務器之家!
原文鏈接:http://www.cnblogs.com/chenpi/p/6409870.html