反射的發展歷史
1996年01月23日,jdk 1.0版本發佈,代號爲Oak(橡樹)。html
這個代號爲Oak(橡樹)的版本,在發佈後的第二年,1997年02月19日,發佈jdk 1.1版本,此次版本發佈中引入了反射機制。java
關於反射機制,因爲年代久遠,能搜索到對於反射機制的記載少之又少,能找到最爲久遠的是一篇題爲《Using Java Reflection》的文章,發表於 1998年1月,文中提到:反射是一個能夠獲取java類、屬性的一個工具,由於它是動態加載的
。oracle
而在另一篇文章《A Button is a Bean》裏解釋道,反射是爲了能把一個類的屬性可視化的展現給用戶,以下圖所示:ide
通俗的解釋就是:不管是公有仍是私有的方法、屬性、構造方法,全均可以用反射進行獲取、進行賦值、調用。聽到這個解釋,是否是感受反射很強。工具
正由於反射的強大,在java世界裏運用的地方有不少,好比:Java類加載和初始化、Java中RTTI、Spring的IOC,。this
如此普遍的運用,只能說反射除了強,用起來確定很爽。我想起個人同事,IT界的刁民,老是熱衷於反射。code
他在講解他是如何運用反射時,嘴角老是壓抑不住的微笑,這種迷戀反射的樣子,像極了愛情。htm
正所謂:反射一開,誰都不愛。(傲嬌)對象
下面就看看反射到底是如何在程序中使用的。blog
反射的概述和使用
反射的概述
JAVA反射機制是在運行狀態中, 對於任意一個類,都可以知道這個類的全部屬性和方法; 對於任意一個對象,都可以調用它的任意一個方法和屬性; 這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
咱們知道class文件是在編譯的時候生成的,Class對象是將class文件讀入內存,併爲之建立一個Class對象。
Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及經過調用類加載器中的defineClass 方法自動構造的。也就是這不須要咱們本身去處理建立,JVM已經幫咱們建立好了。
Class類裏面,包含了一個類應有的全部描述,包括: 字段:Field.java 方法:Method.java 構造方法:Constructor.java 等等...
知道了Class類裏面包含了哪些內容以後,再看一下new一個對象的究竟會發生那些過程:
反射的使用
這裏使用一個Animal類來做爲示範,能夠看到這個類裏的成員變量、方法、構造方法的訪問修飾符既有public、也有private的。下面就將使用反射獲取不一樣修飾符修飾的成員變量、方法、構造方法。
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); } } }