java的反射機制(備忘)
一、概述
瞭解 |
1.使用反射訪問方法和屬性 |
2.使用反射動態建立和訪問陣列 |
|
理解 |
1.反射的概念和應用場合 |
2.使用反射獲取類的資訊 |
|
3.使用反射建立物件 |
二、反射機制
1、反射的概念
在java中的反射機制是指在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。
在電腦科學領域,反射是指一類應用,它們能夠自描述和自控制。
好吧,這句話太正式了,我不是很理解,然後我在網上搜了哈,參考別人的理解,就是我們可以在java程式執行時載入、探知、使用編譯期間完全未知的classes,
也就是能夠看透class的能力,就是java的反射機制。實際上說白了,之前不是說private修飾的類成員,不能被類以外的類或物件訪問嗎,而反射就可以訪問private修飾的類成員,也就是說利用java的反射機制,可以隨便的訪問類或物件的成員(不在乎它的訪問級別)和它的構造方法。
2、java反射的三個動態性質
1) 執行時生成動態物件;
2) 執行期間呼叫方法;
3) 執行時更改屬性。
3、java反射可以實現的功能
1) 在執行時判斷任意一個物件所屬的類;
2) 在執行時構造任意一個類的物件;
3) 在執行時判斷任意一個類所具有的方法和屬性;
4) 在執行時呼叫任意一個物件的方法;
5) 生成動態代理;(這個見動態代理)
4、java反射的應用場合
Java程式中許多物件在執行時都會出現兩種型別:編譯時型別和執行時型別,編譯時的型別由宣告該物件時使用的型別決定,執行時的型別由實際賦給該物件的型別決定,如:
此時p的編譯時型別為Person,執行時型別為Student;因為物件p是引用型別,在編譯時其型別由Person來確定,而在程式執行後發現p引用的內容實際是Student,因為只有在程式執行的時候才能知道p引用的內容改為了Student,所以稱為執行時型別。
除此之外,程式在執行時還可能接收到外部傳入的一個物件,該物件的編譯時型別是Object,但程式又需要呼叫該物件執行時型別的方法。為了解決這些問題,程式需要在執行時發現物件和類的真實資訊
就是一句話,什麼時候用反射,就是在編譯的時候無法預知該物件和類可能屬於哪些類,程式只能依靠執行時資訊來發現該物件和類的真實資訊。這時就需要使用反射。
5、java反射API介紹
Java中用於反射的相關類都是在java.lang.reflect包中
Class類 |
反射的核心類,可以獲取類的屬性、方法等內容資訊 |
Field類 |
表示類的屬性,可以獲取和設定類中屬性的值 |
Method類 |
表示類的方法,它可以用來獲取類中方法的資訊,或者執行方法。 |
Constructor類 |
表示類的構造方法 |
Array類 |
Array類提供了動態建立和訪問java陣列的方法 |
5、使用反射機制的步驟
1) 獲得想操作的類的java.lang.Class物件;
2) 呼叫Class的方法;
3) 使用反射API來操作這些資訊;
7、獲取Class物件的方式
我們已經知道,每個類被載入後,系統就會為該類生成一個對應的Class物件,通過該Class物件就可以訪問到java虛擬機器中的這個類。Java程式中獲得Class物件通常有如下三種方式:
(1)呼叫某個物件的getClass()方法
(2)呼叫某個類的class屬性來獲取該類對應的Class物件
(3)使用Class類的forName()靜態方法
注:(2)和(3)都是根據類來取得該類的Class物件,但相比之下,呼叫某個類的class屬性來獲取該類對應的Class物件這種方式有如下兩種優勢:
² 程式碼更安全,程式在編譯階段就可以檢查需要訪問的class物件是否存在;
² 程式效能更高,因為這種方式無需呼叫方法,所以程式的效能更好。
一般情況下,我們都選擇.class來獲取類,但如果我們只有一個表示類的全名的字串,而我們不知道這個字串的具體內容,此時,我們只能使用Class類的forName()方法來獲取該字串對應的Class物件。不過在使用Class類的forName()方法獲取Class物件時,該方法可能會丟擲一個ClassNotFoundException異常。
8、從Class類中獲取資訊
(1)訪問Class對應的類所包含的構造方法
(2)訪問Class對應的類所包含的方法
方法1
Method getMethod(String name,Class[] params)
返回此Class物件所表示的類的指定的public方法,name引數用於指定方法名稱,params引數是按宣告順序標識該方法引數型別的Class物件的一個數組。
例:c.getMethod(“info”,String.class);
c.getMethod(“info”,String.class,Integer.class);
方法2
Method[] getMethods();
返回此Class物件所表示的類的所有public方法。
方法3
Method getDeclaredMethod(String name,Class[]params);
返回此Class物件所表示的類的指定的方法,與方法的訪問級別無關。
方法4
Method[] getDeclaredMethods();
返回此Class物件所表示的類的全部方法,與方法的訪問級別無關。
(3)訪問Class對應的類所包含的屬性
方法1
Field getField(String name);
返回此Class物件所表示的類的指定的public屬性,name引數用於指定屬性名稱。
例:
c.getField(“age”);
方法2
Field[] getFields();
返回此Class物件所表示的類的所有public 屬性。
方法3
Field getDeclaredField(String name);
返回此Class物件所表示的類的指定屬性,與屬性的訪問級別無關。
Field[] getDeclaredFields();
返回此Class物件所表示的類的全部屬性,與屬性的訪問級別無關。
(4)訪問Class對應的類所包含的註釋
<A extends Annotation>A getAnnotation(Class<A> annotationClass)
:試圖獲取該Class物件所表示類上指定型別的註釋;如果該型別的註釋不存在則返回null。其中annotationClass引數對應於註釋型別的Class物件。
Annotation[] getAnnotations();返回此元素上存在的所有註釋
Annotation[] getDeclaredAnnotations();返回直接存在於此元素上的所有註釋。
(5)訪問Class對應的類所包含的內部類
Class[] getDeclaredClasses();
返回該Class物件所對應類裡包含的全部內部類
(6)訪問Class對應的類所在的外部類
Class getDeclaringClass();
返回該Class物件所在的外部類
(7)訪問該Class物件所對應類所繼承的父類、所實現的介面等int getModifiers();——返回此類或介面的所有修飾符
Class[] getInterfaces();——返回該Class物件對應類所實現的全部介面
Package getPackage();——獲取此類的包
String getName();——以字串形式返回此Class物件所表示的類的名稱
String getSimpleName();——以字串形式返回此Class物件所表示的類的簡
稱
Class getSuperclass();——返回該Class所表示的類的超類對應的Class物件
9、建立物件
通過反射來生成物件,有如下兩種方式
(1) 使用newInstance()建立物件
這種方式要求該Class物件的對應類有預設構造方法,而執行newInstance()方
法時實際上是利用預設構造方法來建立該類的例項。
(2) 使用Constructor物件建立物件
要先使用Class物件獲取指定的Constructor物件,再呼叫Constructor物件的
newInstance()方法來建立該Class物件對應類的例項。通過這種方式可以選擇
使用某個類的指定構造方法來建立例項。
反射技術多用於框架及基礎平臺中,例如Spring
如果我們不想利用預設構造方法來建立java物件,而想利用指定的構造方法來
建立Java物件,則需要利用Constructor物件了,每個Constructor對應一個
構造方法,利用指定構造方法來建立java物件需要三個步驟:
獲取該類的Class物件;
利用Class物件的getConstructor()方法來獲取指定構造方法;
呼叫Constructor的newInstance()方法來建立Java物件。
注:在java中,無論生成某個類的多少個物件,這些物件都會對應於同一個Class
物件,要想使用反射,首先需要獲得待處理類或物件所對應的Class物件。