1、什麼是反射?java
Java反射說的是在運行狀態中,對於任何一個類,咱們都可以知道這個類有哪些方法和屬性。對於任何一個對象,咱們都可以對它的方法和屬性進行調用。咱們把這種動態獲取對象信息和調用對象方法的功能稱之爲反射機制。框架
2、反射的三種方式函數
這裏須要跟你們說一下,所謂反射實際上是獲取類的字節碼文件,也就是.class文件,那麼咱們就能夠經過Class這個對象進行獲取。測試
一、第一種方式code
這個方法實際上是Object的一個方法,Class繼承了Object,因此咱們能夠直接使用。對象
public class Test02 {blog
public static void main(String\[\] args) { // 建立一個對象 Test02 t = new Test02(); // 獲取該對象的Class對象 Class c = t.getClass(); // 獲取類名稱 System.out.println(c.getName()); // com.ms.Test02 }
}繼承
二、第二種方式get
public class Test02 {io
public static void main(String\[\] args) { Class c = Test02.class; // 獲取類名稱 System.out.println(c.getName()); // com.ms.Test02 }
}
三、第三種
這裏須要注意,經過類的全路徑名獲取Class對象會拋出一個異常,若是根據類路徑找不到這個類那麼就會拋出這個異常。
public class Test02 {
public static void main(String\[\] args) { try { // 根據類的全路徑名獲取 Class c = Class.forName("com.ms.Test02"); // 獲取類名稱 System.out.println(c.getName()); // com.ms.Test02 } catch (ClassNotFoundException e) { e.printStackTrace(); } }
}
那麼這3中方式咱們通常選用哪一種方式呢?第一種已經建立了對象,那麼這個時候就不須要去進行反射了,顯得有點畫蛇添足。第二種須要導入類的包,依賴性太強。因此咱們通常選中第三種方式。
3、經過反射獲取類的構造方法、方法以及屬性
一、獲取構造方法
public class Test01 {
public static void main(String\[\] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException { // 加載Class對象 Class c = Class.forName("com.reflect.User"); System.out.println("===========================獲取全部公用的構造方法=============================="); // 獲取全部公用的構造方法 Constructor\[\] constructors = c.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); } System.out.println("=============================獲取全部的構造方法============================"); // 獲取全部的構造方法 Constructor\[\] declaredConstructors = c.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } System.out.println("=============================獲取公有 & 無參的構造方法============================"); Constructor constructor = c.getConstructor(null); System.out.println(constructor); System.out.println("=============================獲取公有 & 有參的構造方法============================"); Constructor constructor1 = c.getConstructor(new Class\[\]{String.class, Integer.class, String.class}); System.out.println(constructor1); System.out.println("=============================獲取私有 & 有參 構造方法============================"); Constructor declaredConstructor1 = c.getDeclaredConstructor(new Class\[\]{String.class}); System.out.println(declaredConstructor1); }
}
結果:
二、獲取類屬性
public class Test02 {
public static void main(String\[\] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { // 獲取Class對象 Class<?> clazz = Class.forName("com.reflect.User"); System.out.println("=====獲取全部的公共字段====="); Field\[\] fields = clazz.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("=====獲取全部的字段(公開的、私有的)====="); Field\[\] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("=====獲取公有字段並使用====="); // 獲取指定公有字段 Field field = clazz.getField("name"); // 獲取一個公有構造方法,而後實例化 Object obj = clazz.getConstructor().newInstance(); // 爲屬性設置值 field.set(obj, "張三"); // 測試,看設置的值是否成功 User user = (User) obj; System.out.println(user.getName()); System.out.println("=====獲取私有字段並使用====="); Field field1 = clazz.getDeclaredField("sex"); // 獲取構造函數,實例化對象 Object obj1 = clazz.getConstructor().newInstance(); // 暴力反射 field1.setAccessible(true); // 給屬性設置值 field1.set(obj1, "男"); // 測試 User u = (User) obj1; System.out.println(u.getSex()); }
}
結果
這裏須要注意,在獲取私有屬性的時候若是沒有進行暴力反射,那麼會拋出下面這個異常。
三、獲取類中的方法
先定義幾個方法
public void method1(String str) {
System.out.println("public 修飾的方法");
}
private void method2() {
System.out.println("private 修飾的方法");
}
String method3(String name, Integer age, String sex) {
System.out.println("默認修飾 " + name + " " + sex + " " + age + "歲"); return name + sex + age;
}
protected void method4() {
System.out.println("protected 修飾的方法");
}
正題
public class Test03 {
public static void main(String\[\] args) throws Exception { // 獲取Class對象 Class<?> clazz = Class.forName("com.reflect.User"); System.err.println("======獲取全部的public修飾的方法====="); Method\[\] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } Thread.sleep(1000); System.err.println("======獲取全部的方法====="); Method\[\] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } Thread.sleep(1000); System.err.println("======獲取特定方法(帶參)並使用====="); Method method1 = clazz.getMethod("method1", String.class); System.out.println(method1); Thread.sleep(1000); System.err.println("======獲取特定方法(不帶參)並使用====="); Method method2 = clazz.getDeclaredMethod("method2"); System.out.println(method2); System.err.println("======獲取特定方法(多個參數)並使用====="); Method method3 = clazz.getDeclaredMethod("method3", String.class, Integer.class, String.class); // 獲取構造方法,實例化一個對象 Object obj = clazz.getConstructor().newInstance(); // 給方法傳值 Object invoke = method3.invoke(obj, "小濤", 24, "男"); // 測試 System.out.println(invoke); }
}
結果
這裏須要注意的就是當一個方法須要傳入多個參數值的時候,必定要注意。踩了一點坑。
4、反射執行main方法
public class Main {
public static void main(String\[\] args) { System.out.println("main方法執行了"); }
}
反射調用
public class Test04Main {
public static void main(String\[\] args) { try { // 獲取Class對象 Class<?> clazz = Class.forName("com.reflect.Main"); // 獲取Main方法 Method method = clazz.getMethod("main", java.lang.String\[\].class); // 調用 method.invoke(null, (Object) new String\[\]{"a"}); } catch (Exception e) { e.printStackTrace(); } }
}
這裏須要告訴你們,在導String包的時候千萬要看清楚,我在這填了20多分鐘的坑。
5、總結
看到這裏你已經對反射有了一個簡單的瞭解,能夠使用反射獲取一些屬性方法,其實咱們平時寫代碼不多用到反射技術,可是在咱們使用的一些主流框架中反射技術應用是很是普遍的,因此學好反射也是很是有必要的。
今天就寫到這裏,下篇給你們分享一下利用反射作一些有應用型的例子。
感受不錯就給小濤一個贊吧!