反射的發展歷史
1996年01月23日,jdk 1.0版本發布,代號為Oak(橡樹)。
這個代號為Oak(橡樹)的版本,在發布後的第二年,1997年02月19日,發布jdk 1.1版本,這次版本發布中引入了**反射**機制。
通俗的解釋就是:無論是公有還是私有的方法、屬性、構造方法,全都可以用反射進行獲取、進行賦值、調用。聽到這個解釋,是不是感覺反射很強。
正因為反射的強大,在java世界裡運用的地方有很多,比如:Java類加載和初始化、Java中RTTI、Spring的IOC,。
如此廣泛的運用,只能說反射除了強,用起來肯定很爽。我想起我的同事,IT界的刁民,總是熱衷於反射。
他在講解他是如何運用反射時,嘴角總是壓抑不住的微笑,這種迷戀反射的樣子,像極了愛情。
正所謂:反射一開,誰都不愛。(傲嬌)
下面就看看反射究竟是如何在程序中使用的。
反射的概述和使用
反射的概述
JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
反射的使用
這裡使用一個Animal類來作為示範,可以看到這個類裡的成員變量、方法、構造方法的訪問修飾符既有public、也有privat的 。下面就將使用反射獲取不同修飾符修飾的成員變量、方法、構造方法。
package com.shuai.ioc.ref;public class Animal { /** * 動物名字 */ public String name; /** * 動物年齡 */ protected int age; @Override public String toString() { return "Animal{" + "name='" + name + '\'' + ", age=" + age + '}'; } /** * 默認的構造方法 * * @param name */ Animal(String name) { System.out.println("執行了" + "默認的構造方法 " + name); } /** * 無參構造方法 */ public Animal() { System.out.println("執行了" + "無參構造方法 "); } /** * 有一個參數的構造方法 * * @param name */ public Animal(char name) { System.out.println("執行了" + "有一個參數的構造方法 name:" + name); } /** * 有多個參數的構造方法 * * @param name * @param age */ public Animal(String name, int age) { System.out.println("執行了" + "有多個參數的構造方法 name:" + name + "age:" + age); } /** * protected的構造方法 * * @param n */ protected Animal(boolean n) { System.out.println("執行了" + "受保護的構造方法 n:" + n); } /** * 私有構造方法 * * @param age */ private Animal(int age) { System.out.println("執行了" + "私有構造方法 age:" + age); this.name = "私有構造方法調用成功"; this.age = age; } /** * 公有方法 * * @param s */ public void public1(String s) { System.out.println("調用了" + "公有的方法" + ": public1 , s:" + s); } /** * protected的方法 */ protected void protected2() { System.out.println("調用了" + "protected的方法" + ": protected2 "); } /** * 友好的方法 */ void friendly1() { System.out.println("調用了" + "友好的方法" + ": friendly1 "); } /** * 私有方法 * * @param age * @return */ private String private1(int age) { System.out.println("調用了" + "私有方法" + ": private1 ,age:" + age); return age + ""; }}用反射獲取類的構造方法
在Class類中,提供一系列獲取被反射類構造方法的方法。
批量獲取構造方法的方法public Constructor[] getConstructors():所有」公有的」構造方法public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、默認、公有)獲取單個的方法,並調用public Constructor getConstructor(Class... parameterTypes):獲取單個的」公有的」構造方法public Constructor getDeclaredConstructor(Class... parameterTypes):獲取」某個構造方法」可以是私有的,或受保護、默認、公有;調用構造方法newInstance(Object… initargs)package com.shuai.ioc.ref;import com.shuai.ioc.Book;import java.lang.reflect.Constructor;public class ConstructorsTest {public static void main(String[] args) throws Exception { //1.加載Class對象 Class clazz = Class.forName("com.shuai.ioc.ref.Animal"); //2.獲取所有公有構造方法 System.out.println("所有公有構造方法"); Constructor[] conArray = clazz.getConstructors(); for (Constructor c : conArray) { System.out.println(c); } // 所有的構造方法,公有、私有都行 System.out.println(""); System.out.println("所有的構造方法,包括:私有、受保護、默認、公有"); conArray = clazz.getDeclaredConstructors(); for (Constructor c : conArray) { System.out.println(c); } // 獲取公有、無參的構造方法 System.out.println(""); System.out.println("獲取公有、無參的構造方法"); Constructor con = clazz.getConstructor(null); System.out.println("con = " + con); //調用構造方法 Object obj = con.newInstance(); // 獲取私有構造方法 System.out.println(""); System.out.println("獲取私有構造方法,並調用"); con = clazz.getDeclaredConstructor(int.class); System.out.println(con); //暴力訪問,忽略掉訪問修飾符 con.setAccessible(true); //調用構造方法 Animal animal = (Animal) con.newInstance(1); System.out.println(animal.toString());}}用反射獲取類的方法
在Class類中,提供一系列獲取被反射類構造方法的方法。
批量的public Method[] getMethods():獲取所有」公有方法」;(包含了父類的方法也包含Object類)public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)獲取單個的public Method getMethod(String name,Class<?>... parameterTypes),name: 方法名;Class ...:形參的Class類型對象public Method getDeclaredMethod(String name,Class<?>... parameterTypes),obj:要調用方法的對象;args:調用方式時所傳遞的實參;調用方法public Object invoke(Object obj,Object... args),obj:要調用方法的對象;args:調用方式時所傳遞的實參;package com.shuai.ioc.ref;import java.lang.reflect.Method;public class MethodClassTest {public static void main(String[] args) throws Exception { //1.獲取Class對象 Class stuClass = Class.forName("com.shuai.ioc.ref.Animal"); //2.獲取所有公有方法 System.out.println("獲取所有 公有 方法"); stuClass.getMethods(); Method[] methodArray = stuClass.getMethods(); for (Method m : methodArray) { System.out.println(m); } System.out.println(); System.out.println("獲取所有的方法,包括私有的"); methodArray = stuClass.getDeclaredMethods(); for (Method m : methodArray) { System.out.println(m); } System.out.println(); System.out.println("獲取公有的public1()方法"); Method m = stuClass.getMethod("public1", String.class); System.out.println(m); //實例化一個Student對象 Object obj = stuClass.getConstructor().newInstance(); m.invoke(obj, "this is name value"); System.out.println(); System.out.println("獲取私有的private1()方法"); m = stuClass.getDeclaredMethod("private1", int.class); System.out.println(m); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj, 20);//需要兩個參數,一個是要調用的對象(獲取有反射),一個是實參 System.out.println("返回值:" + result);}}用反射獲取類的欄位
在Class類中,提供一系列獲取被反射類構造方法的方法。
批量的Field[] getFields():獲取所有的」公有欄位」Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、默認、公有;獲取單個的public Field getField(String fieldName):獲取某個」公有的」欄位;public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)設置欄位的值public void set(Object obj,Object value):obj:要設置的欄位所在的對象;value:要為欄位設置的值;package com.shuai.ioc.ref;import java.lang.reflect.Field;public class FieldsTest {public static void main(String[] args) throws Exception { //1.獲取Class對象 Class animalClass = Class.forName("com.shuai.ioc.ref.Animal"); //2.獲取欄位 System.out.println("獲取所有公有的欄位"); Field[] fieldArray = animalClass.getFields(); for (Field f : fieldArray) { System.out.println(f); } System.out.println(); System.out.println("獲取所有的欄位(包括私有、受保護、默認的)"); fieldArray = animalClass.getDeclaredFields(); for (Field f : fieldArray) { System.out.println(f); } System.out.println(); System.out.println("獲取公有欄位並調用"); Field f = animalClass.getField("name"); System.out.println(f); //獲取一個對象 Object obj = animalClass.getConstructor().newInstance();//產生Student對象--》Student stu = new Student(); //為欄位設置值 f.set(obj, "dog");//為Student對象中的name屬性賦值--》stu.name = "劉德華" //驗證 Animal stu = (Animal) obj; System.out.println("驗證name:" + stu.name); System.out.println(); System.out.println("獲取私有欄位並調用"); f = animalClass.getDeclaredField("name"); System.out.println(f); f.setAccessible(true);//暴力反射,解除私有限定 f.set(obj, "this is name value"); System.out.println("驗證name:" + stu);}}反射越過泛型檢查
編寫代碼時,如果我們設置容器list為String類型,在調用add方法插入數據時入參傳了其他類型,編譯時會無法成功,但是通過反射卻可以執行,實例代碼:
package com.shuai.ioc.ref;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;/* * 通過反射越過泛型檢查 * */public class IgnoreType { public static void main(String[] args) throws Exception { List<String> list = new ArrayList<>(); list.add("one"); //反射獲取list對象 Class listClass = list.getClass(); // 調用list對象的add方法 Method m = listClass.getMethod("add", Object.class); m.invoke(list, 100); //輸出驗證 for (Object obj : list) { System.out.println(obj); } }}