Java的一切都是對象java
Object是反射的源頭數組
Class是反射的導演函數
在Java程序運行時,JVM會對全部的對象維護一個獨一無二的類型標識,這就是Class對象。spa
Java的基本類型和關鍵字void也對應一個Class對象。
相同元素類型和維數的數組也對應一個Class對象。code
獲取Class對象的幾種方法:對象
Class對象有一些重要的方法:繼承
上述系列中包含Declared系列,能夠獲取當前對象的全部類型的反射(包含private),可是不能獲取父類的反射接口
Constructor,Field,Method都是Class導演的三大利器,它們都位於java.lang.reflect
包下,接下來將分別對這三大利器進行展現。get
經過Class對象獲取到的Constructor對象以後,最經常使用的操做就是用來實例化對象,調用newInstance方法便可。string
其實在Class對象中也有一個newInstance方法,也能夠用來實例化對象,它們的區別是什麼呢?
Demo
//Class.newInstance()
//只能調用public屬性的無參構造函數
A a = (A)Class.forName(A.class.getName()).newInstance();
//Constructor.newInstance()
Class c= Class.forName(A.class.getName());
/*如下調用無參的、私有構造函數*/
//得到無參構造
Constructor c0=c.getDeclaredConstructor();
//設置無參構造是可訪問的
c0.setAccessible(true);
A a0=(A)c0.newInstance();
//調用無參構造函數,生成對象實例
/*如下調用帶參的、私有構造函數*/
Constructor c1=c.getDeclaredConstructor(new Class[]{int.class,int.class});
c1.setAccessible(true);
//調用有參構造函數,生成對象實例
A a1=(A)c1.newInstance(new Object[]{5,6});
複製代碼
使用場景:
若是使用接口模式,使用new建立一個門的對象,Door door = new WoodenDoor(),當以換成其餘門,須要修改代碼,Door door = new OtherDoor()。因此咱們須要使用工廠模式,須要什麼門就生產什麼門,若是咱們再使用newInstance()方法來生產,則只須要修改配置文件便可。
經過Class對象獲取到的Field對象以後,咱們就能夠自由的查看和設置對象的屬性值。
關鍵方法:
Demo
//獲取Class對象
Class aClass = MyObject.class
//經過Class對象獲取Field對象
Field field = aClass.getDeclaredField("someField");
//設置可訪問權限
field.setAccessible(true);
MyObject objectInstance = new MyObject();
//獲取特定的對象的變量屬性值
Object value = field.get(objectInstance);
//給特定對象的變量設置屬性
field.set(objetInstance, value);
複製代碼
由於Constructor,Field,Method都繼承自AccessibleObject類,全部都擁有setAccessible方法,我的感受setAccessible有點窺探隱私的感受,哈哈哈,不知道Class導演怎麼看。
經過Class對象獲取到的Method對象以後,想都不用想啊,獲取一個方法不調用它幹嗎,因此咱們最經常使用的操做應該就是invoke方法。
相信你們對invoke並不會陌生,由於不少的異常,最後都會定位到invoke方法。
java.lang.NullPointerException
at ......
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
複製代碼
invoke(Object receiver, Object… args),能夠分爲兩種,傳遞receiver參數表示調用特定對象的方法,傳null表示調用靜態方法。
//獲取一個方法名爲doSomesthing,參數類型爲String的方法
Method method = MyObject.class.getMethod("doSomething", String.class);
//調用靜態的doSomesthing方法,傳遞參數"parameter-value1"
Object returnValue = method.invoke(null, "parameter-value1");
複製代碼
本文只是對Clss對象以及reflect包下的對象進行簡單的使用說明,關於反射的實現和原理,還有待於深刻研究。例如AccessibleObject對象以及對應相關xxxAccessor的實現。