1 Class類
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
1.1 獲取Class對象的三種方式:
public class Person { private String name; public int age; static{ System.out.println("靜態代碼塊"); } public Person(){ System.out.println("空參構造"); } public Person(String name,int age){ this.name=name; this.age=age; System.out.println("Person(String name,int age)"); } private Person(String name){ this.name=name; System.out.println("Person(String name)"); } public void eat(){ System.out.println("公共空參方法"); } public void sleep(String name){ System.out.println("公共有參方法"); } public void smoke(){ System.out.println("私有空參構造"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException { //1.通過getClass方法獲取, 通過對象獲取 Person p=new Person(); Class c1=p.getClass(); System.out.println(c1); //2.通過類名獲取 Class c2=Person.class; System.out.println(c2); System.out.println(c1==c2); System.out.println(c1.equals(c2)); //3.通過完整的包名+類名獲取 Class c3=Class.forName("com.oracle.demo03.Person"); System.out.println(c3); } }
2 通過反射獲取構造方法並使用
在反射機制中,把類中的成員(構造方法、成員方法、成員變量)都封裝成了對應的類進行表示。其中,構造方法使用類Constructor表示。可通過Class類中提供的方法獲取構造方法:
public class Demo02 { //構造方法 Constructor //成員變量 Field //成員方法 Method public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //反射獲取構造方法 //1.獲取Person.Class文件對象 Class c=Class.forName("com.oracle.demo03.Person"); //獲取所有公共的構造方法(數組) /*Constructor[]cons=c.getConstructors(); //遍歷 for(Constructor con:cons){ System.out.println(con); }*/ //獲取某個公共構造方法 /*Constructor con1=c.getConstructor(String.class,int.class); System.out.println(con1); //通過構造方法創建對象 Object obj=con1.newInstance("張三",18); System.out.println(obj);*/ //獲取所有構造方法數組 /*Constructor[]cons=c.getDeclaredConstructors(); for(Constructor con:cons){ System.out.println(con); }*/ //獲取某個私有構造方法 Constructor con=c.getDeclaredConstructor(String.class); //System.out.println(con); //暴力反射 con.setAccessible(true); Object obj=con.newInstance("熊大"); System.out.println(obj); } }
3 通過反射獲取成員變量和成員方法並使用
在反射機制中,把類中的成員變量使用類Field表示。可通過Class類中提供的方法獲取成員變量:
在反射機制中,把類中的成員方法使用類Method表示。可通過Class類中提供的方法獲取成員方法:
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { //獲取字節碼文件對象 Class c=Class.forName("com.oracle.demo01.Person"); //獲取所有的成員變量 /*Field[]fields=c.getDeclaredFields(); //遍歷 for(Field field:fields){ System.out.println(field); }*/ //獲取某個成員變量並賦值 /*Field field=c.getDeclaredField("age"); Object obj=new Person(); field.set(obj, 18); System.out.println(obj);*/ //獲取所有成員方法 /*Method[]methods=c.getDeclaredMethods(); //遍歷 for(Method method:methods){ System.out.println(method); }*/ //獲取單個成員方法 Method method=c.getMethod("sleep", String.class); //調用方法 Object obj=c.newInstance(); method.invoke(obj, "張三");}
}
4 反射練習
4.1 泛型擦除
思考,將已存在的ArrayList<Integer>集合中添加一個字符串數據,如何實現呢?
其實程序編譯後產生的.class文件中是沒有泛型約束的,這種現象我們稱爲泛型的擦除。那麼,我們可以通過反射技術,來完成向有泛型約束的集合中,添加任意類型的元素
public class Demo02 { public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { //泛型擦除 ArrayList<Integer>arr=new ArrayList<Integer>(); //獲取ArrayList的字節碼文件對象 Class c=arr.getClass(); //通過反射的方式獲取add方法 Method add=c.getMethod("add", Object.class); add.invoke(arr, "aaa"); System.out.println(arr); } }
4.2 反射配置文件
通過反射配置文件,運行配置文件中指定類的對應方法
讀取properties文件中的數據,通過反射技術,來完成Person對象的創建
public class Demo01 { public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //明確配置文件的路徑 FileReader fr=new FileReader("src/com/oracle/demo02/config.properties"); //創建Properties集合 Properties pro=new Properties(); //從配置文件中讀取鍵值對到集合中 pro.load(fr); //從集合中獲取完整的包名+類名 String ClassName=pro.getProperty("ClassName"); //獲取方法名 String MethodName=pro.getProperty("MethodName"); //通過反射獲取字節碼文件對象 Class c=Class.forName(ClassName); //創建對象 Object obj=c.newInstance(); //獲取方法 Method method=c.getMethod(MethodName); //調用方法 method.invoke(obj); } }