Class類與java.lang.reflect類庫一起對反射進行了支持,該類庫包含Field、Method和Constructor類,這些類的對象由JVM在啟動時創建,用以表示未知類里對應的成員。這樣的話就可以使用Contructor創建新的對象,用get()和set()方法獲取和修改類中與Field對象關聯的字段,用invoke()方法調用與Method對象關聯的方法。另外,還可以調用getFields()、getMethods()和getConstructors()等許多便利的方法,以返回表示字段、方法、以及構造器對象的數組,這樣,對象信息可以在運行時被完全確定下來,而在編譯時不需要知道關於類的任何事情。
首先創建一個類
1 public class Per { 2 public String name="sunshine"; 3 private int age=28; 4 public double weight=65.50; 5 6 public Per(){ 7 System.out.println("測試反射獲取公有無參構造函數"); 8 } 9 private Per(String name){ 10 this.name=name; 11 System.out.println("測試反射獲取私有有參構造函數"); 12 } 13 public Per(String name,int age){ 14 this.name=name; 15 this.age=age; 16 System.out.println("測試反射獲取公有有多個參數構造函數name:"+name+" age:"+age);17 } 18 public String methodT1(){ 19 System.out.println("測試反射獲取公有無參方法"); 20 return null; 21 } 22 public String methodT1(String name,int age){ 23 System.out.println("測試反射獲取公有多個參方法"); 24 System.out.println(name+":"+age); 25 return null; 26 } 27 private String methodT1(String name){ 28 System.out.println("測試反射獲取私有有參方法"); 29 System.out.println("name:"+name); 30 return null; 31 } 32 public String methodT2(int[] arr,String[] str){ 33 System.out.println("測試反射獲取公有有數組參方法"); 34 System.out.println("int[] arr:"+arr+"String[] str:"+str); 35 return null; 36 } 37 public static void main(String[] args) { 38 System.out.println("測試反射獲取main方法"); 39 } 40 }
1.使用java反射獲取類的構造函數(公有、私有)(有參,無參)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 import org.junit.AfterClass; 6 import org.junit.BeforeClass; 7 import org.junit.Test; 8 /** 9 * 測試使用java反射獲取類的構造函數並創建對象 10 * @author Sunshine 11 * 12 */ 13 public class ReflectPer { 14 private static Class class1; 15 //因為java反射獲取類時都需要加載類,在這里我就使用Junit的@beforeclass來去加載類,不用在每個測試方法中重復創建 16 //注:@beforeclass在執行測試方法前運行 17 @BeforeClass 18 public static void beforeClass() throws Exception{ 19 System.out.println("====測試方法啟動前先加載類===="); 20 class1 = Class.forName("myPractise.Per");//加載類 21 } 22 //獲取類的公有無參構造函數,並創建對象 23 @Test 24 public void test1() throws Exception{ 25 Constructor constructor = class1.getConstructor(null);//獲取公有無參構造器,值為null代表獲取無參構造器 26 Per per = (Per) constructor.newInstance(null);//創建對象,返回的是Object類型要強轉 27 System.out.println(per.name);//可以調用類的屬性-----成功 28 } 29 //獲取類的公有參構造函數,並創建對象 30 @Test 31 public void test2()throws Exception{ 32 Constructor constructor = class1.getConstructor(String.class,int.class);//獲取公有多個參數構造器,參數為構造器中參數的類型 33 Per per = (Per)constructor.newInstance("baby",24);//創建對象 34 } 35 //獲取類的私有有參構造函數,並創建對象 36 @Test 37 public void test3()throws Exception{ 38 Constructor constructor = class1.getDeclaredConstructor(String.class);//獲取公有多個參數構造器,參數為構造器中參數的類型 39 constructor.setAccessible(true);//暴力反射,只有將屬性設置為true才可以創建對象 40 Per per = (Per)constructor.newInstance("baby"); 41 System.out.println(per.weight);//可以調用類的屬性-----成功 42 //注:通常情況下一個類不可以訪問另一個類的私有的屬性,方法。。但是通過java反射可以 43 } 44 @AfterClass 45 public static void afterClass(){ 46 System.out.println("===測試完成將對象賦值為null==="); 47 } 48 }
2.使用java反射獲取類的方法(公有、私有)(有參,無參)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 import org.junit.AfterClass; 6 import org.junit.BeforeClass; 7 import org.junit.Test; 8 /** 9 * 測試使用java反射獲取類方法 10 * @author Sunshine 11 * 12 */ 13 public class ReflectPer { 14 private static Class class1; 15 private static Per per; 16 //因為java反射獲取類時都需要加載類,在這里我就使用Junit的@beforeclass來去加載類,不用在每個方法中重復創建 17 //注:@beforeclass在執行測試方法前運行 18 @BeforeClass 19 public static void beforeClass() throws Exception{ 20 System.out.println("====測試方法啟動前先加載類===="); 21 class1 = Class.forName("myPractise.Per");//加載類 22 per = (Per) class1.getConstructor(null).newInstance(null);//使用反射創建對象 23 } 24 25 //獲取類的公有無參方法 26 @Test 27 public void test4()throws Exception{ 28 Method method = class1.getMethod("methodT1", null);//獲取指定的方法,參數為方法名和該方法的參數類型,因為我們這是測試無參的方法,所以傳入null 29 method.invoke(per, null);//使用invoke方法來調用,參數為指定對象,該方法傳入的參數,因為我們這是測試無參的方法,所以傳入null 30 } 31 //獲取類的公有有參方法 32 @Test 33 public void test5()throws Exception{ 34 Method method = class1.getMethod("methodT1", String.class,int.class);//獲取指定的方法,參數為方法名和該方法的參數類型 35 method.invoke(per, "sunshine",25);//使用invoke方法來調用,參數為指定對象,該方法傳入的參數 36 } 37 @Test 38 public void test6()throws Exception{ 39 Method method = class1.getDeclaredMethod("methodT1", String.class);//獲取指定的方法,參數為方法名和該方法的參數類型 40 method.setAccessible(true);//暴力反射,默認為false,未設置則調用類的私有方法不成功 41 method.invoke(per, "sunshine");//使用invoke方法來調用,參數為指定對象,該方法傳入的參數 42 System.out.println(method.getReturnType());//獲取到該類指定方法的返回值類型 43 } 44 @Test 45 public void test7()throws Exception{ 46 Method method = class1.getMethod("methodT2", int[].class,String[].class); 47 method.invoke(per, new int[]{1,2},new String[]{"AA","BB"}); 48 } 49 //獲取某個類的main方法比較特殊也可以說是只要傳入的參數為單個數組特殊 50 //jdk5之后新增特性--可變參數 51 //在加載時會將傳入的數組進行拆分,這樣就會報錯,java.lang.IllegalArgumentException: wrong number of arguments 錯誤的參數個數 52 //這時候我們可以欺騙一下虛擬機,告訴他我們傳入的是一個對象將new String[]{"AA","BB"}換成(Object)new String[]{"AA","BB"} 53 @Test 54 public void test8()throws Exception{ 55 Method method = class1.getMethod("main",String[].class); 56 method.invoke(per,(Object)new String[]{"AA","BB"}); 57 } 58 @AfterClass 59 public static void afterClass(){ 60 System.out.println("===測試完成將對象賦值為null==="); 61 } 62 }
3.使用java反射獲取類的屬性(公有、私有)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 import java.util.Iterator; 5 6 import org.junit.AfterClass; 7 import org.junit.BeforeClass; 8 import org.junit.Test; 9 10 /** 11 * 測試使用java反射獲取類的屬性 12 * 13 * @author Sunshine 14 * 15 */ 16 public class ReflectPer { 17 private static Class class1; 18 private static Per per; 19 20 // 因為java反射獲取類時都需要加載類,在這里我就使用Junit的@beforeclass來去加載類,不用在每個測試方法中重復創建 21 // 注:@beforeclass在執行測試方法前運行 22 @BeforeClass 23 public static void beforeClass() throws Exception { 24 System.out.println("====測試方法啟動前先加載類===="); 25 class1 = Class.forName("myPractise.Per");// 加載類 26 per = (Per) class1.getConstructor(null).newInstance(null);// 使用反射創建對象 27 } 28 // 公有屬性 29 @Test 30 public void test9() throws Exception { 31 // 獲取某個屬性,參數是屬性名 32 Field field = class1.getField("name"); 33 // 輸出屬性值,需要傳入指定對象 34 System.out.println(field.get(per)); 35 // 獲取屬性的類型 36 System.out.println(field.getType()); 37 // 獲取多個屬性 38 Field[] field1 = class1.getFields(); 39 // 增強for循環Jdk1.5后的新特性,只適用於數組和實現了Iterator的集合 40 for (Field str : field1) { 41 System.out.println(str); 42 } 43 // 設置屬性值 44 field.set(per, "baby"); 45 System.out.println(field.get(per)); 46 } 47 //私有屬性 48 @Test 49 public void test10() throws Exception { 50 Field field = class1.getDeclaredField("age"); 51 field.setAccessible(true);//暴力反射 52 System.out.println(field.get(per)); 53 } 54 55 @AfterClass 56 public static void afterClass() { 57 System.out.println("===測試完成將對象賦值為null==="); 58 } 59 }