Java反射指的是在運行狀態時,可以獲取類的屬性和方法或者修改類運行時行爲的過程。java
java.lang.Class類提供了不少方法用於獲取元數據、檢查和改變類運行時的行爲。spring
Java的反射主要涉及java.lang和java.lang.reflect包下的類。數組
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 | 返回類中指定參數類型的方法 |
有三種方式,以下:工具
forName()方法示例測試
可用於動態加載,當你知道類的全限定名時,可使用該方式。注意原始數據類型不適用該方法;this
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()); } }
getClass()方法示例:spa
從實例對象中獲取Class對象hibernate
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()); } }
.class語法示例翻譯
做用於類名上,也可應用於原始數據類型,以下所示:
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()); } }
如下方法可用於判斷Class對象對應的類型:
1) public boolean isInterface(): 是否對應接口 |
2) public boolean isArray(): 是否對應數組 |
3) public boolean isPrimitive(): 是否對應原始數據類型 |
代碼示例:
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); } } }
有兩種方式,以下:
因此,一般來說,第二種方式比第一種使用範圍更廣。
Class對象調用newInstance()方法示例
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); } } }
Constructor對象調用newInstance()方法示例
注意這裏能夠根據傳入參數的類型來獲得指定的構造方法,還能夠改變構造方法的訪問權限限制。
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); } } }
經過反射,咱們能夠調用其它類的私有方法,主要涉及java.lang.Class和java.lang.reflect.Method類;
其中主要是用到了Method類的setAccessible方法和invoke方法,前者修改訪問權限,後者調用方法。
經過調用有參私有方法示例:
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命令能夠反彙編java的字節碼文件,展現class文件中的字段屬性、構造方法、普通方法信息;
使用說明:
javap java.lang.Object示例
javap -c Test示例:
寫個簡單的Test類,以下:
package tmp; class Simple { } public class Test { public static void main(String args[]) { System.out.println("Hello"); } }
輸入javap -c Test:
基本屬於翻譯,作了小部分修改