轉載自:[https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html]
12 反射
1. 引入反射
通常情況下,調用一個類的方法的步驟如下:
- 創建該類的對象。
- 調用該對象的方法。
通過這種方式調用方法時,必須要知道類的定義以及類的所有屬性和方法。代碼如下:
Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);
另一種調用類方法的方式是:反射。示例如下:
//獲取類的class對象
Class clz = Class.forName("com.chenshuyi.reflect.Apple");
//獲取類的指定方法的method對象
Method method = clz.getMethod("setPrice", int.class);
//獲取類的默認構造器
Constructor constructor = clz.getConstructor();
//創建類的對象
Object object = constructor.newInstance();
//調用方法
method.invoke(object, 4);
上面兩段代碼的執行結果,其實是完全一樣的。但是其思路完全不一樣,第一段代碼在未運行時就已經確定了要運行的類(Apple),而第二段代碼則是在運行時通過字符串值才得知要運行的類(com.chenshuyi.reflect.Apple
)。
2. 反射定義
反射就是在運行時才知道要操作的類是什么,并且可以在運行時獲取類的完整構造,并調用對應的方法。
3. 示例的完整代碼
public class Apple {private int price;public int getPrice(){return price;}public void setPrice(int price) {this.price = price;}public static void main(String[] args) throws Exception{//正常的調用Apple apple = new Apple();apple.setPrice(5);System.out.println("Apple Price:" + apple.getPrice());//使用反射調用Class clz = Class.forName("com.chenshuyi.api.Apple");Method setPriceMethod = clz.getMethod("setPrice", int.class);Constructor appleConstructor = clz.getConstructor();Object appleObj = appleConstructor.newInstance();setPriceMethod.invoke(appleObj, 14);Method getPriceMethod = clz.getMethod("getPrice");System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));}
}
4. 反射調用的步驟
一般情況下我們使用反射獲取一個對象的步驟:
獲取類的 Class 對象實例
Class clz = Class.forName("com.zhenai.api.Apple");
根據 Class 對象實例獲取 Constructor 對象
Constructor appleConstructor = clz.getConstructor();
使用 Constructor 對象的 newInstance 方法獲取反射類對象
Object appleObj = appleConstructor.newInstance();
如果要調用某一個方法,則需要經過下面的步驟:
獲取方法的 Method 對象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
利用 invoke 方法調用方法
setPriceMethod.invoke(appleObj, 14);
5. 反射常用的 API
1. 獲取反射中的 Class 對象
在反射中,要獲取一個類或調用一個類的方法,我們首先需要獲取到該類的 Class 對象。在 Java API 中,獲取 Class 類對象有三種方法:
使用 Class.forName 靜態方法。當你知道類的全路徑名時,你可以使用該方法獲取 Class 類對象。
Class clz = Class.forName("java.lang.String");
使用 類型名.class 。
Class clz = String.class;
使用類對象的 getClass() 方法。
String str = new String("Hello"); Class clz = str.getClass();
2. 通過反射創建類對象
通過反射創建類對象主要有兩種方式(newInstance()
的返回值是 Object):
通過 Class 對象的
newInstance()
方法Class clz = Apple.class; Apple apple = (Apple)clz.newInstance();
通過 Constructor 對象的
newInstance()
方法。Class clz = Apple.class; Constructor constructor = clz.getConstructor(); Apple apple = (Apple)constructor.newInstance();
通過 Constructor 對象創建類對象可以選擇特定構造方法,而通過 Class 對象則只能使用默認的無參數構造方法。下面的代碼就調用了一個有參數的構造方法進行了類對象的初始化:
Class clz = Apple.class;
Constructor constructor = clz.getConstructor(String.class, int.class);
Apple apple = (Apple)constructor.newInstance("紅富士", 15);
3. 通過反射獲取類屬性、方法、構造器
獲取類的屬性
Field getField(String name)
:獲取 Class 對象對應類的指定公有屬性。Field[] getFields()
:獲取 Class 對象對應類的所有公有屬性(包括從父類中繼承的公有屬性),無法獲取類的私有屬性。Field[] getDeclaredFields()
:獲取 Class 對象對應類的所有屬性(僅限本類中定義的公有、默認、保護、私有屬性,不包括從父類中繼承的屬性)。Field getDeclaredField(String name)
:獲取 Class 對象對應類的指定屬性(僅限本類中定義的公有或默認或保護或私有屬性,不包括從父類中繼承的屬性)。
獲取類的方法
Method getMethod(String name, Class<?>... parameterTypes)
:獲取 Class 對象對應類的指定公有方法。Method[] getMethods()
: 獲取 Class 對象對應類的所有公有方法(包括從父類中繼承的公有方法),無法獲取類的私有方法。Method[] getDeclaredMethods()
:獲取 Class 對象對應類的所有方法(僅限本類中定義的公有、默認、保護、私有方法,不包括從父類中繼承的方法,以及本類的構造器)。Method getDeclaredMethod(String name, Class<?>... parameterTypes)
:獲取 Class 對象對應類的指定公有方法(僅限本類中定義的公有或默認或保護或私有方法,不包括從父類中繼承的方法)。
獲取類的構造器
Constructor<T> getConstructor(Class<?>... parameterTypes)
:獲取 Class 對象對應類的指定公有構造器。Constructor<?>[] getConstructors()
:獲取 Class 對象對應類的所有公有構造器。Constructor<?>[] getDeclaredConstructors()
:獲取 Class 對象對應類的所有構造器。Constructor<?>[] getDeclaredConstructor(Class<?>... parameterTypes)
:獲取 Class 對象對應類的指定構造器(公有或私有)。