- Offer來了:Java面試核心知識點精講(原理篇)
- 王磊
- 1646字
- 2020-04-03 12:50:10
2.3 反射機制
2.3.1 動態語言的概念
動態語言指程序在運行時可以改變其結構的語言,比如新的屬性或方法的添加、刪除等結構上的變化。JavaScript、Ruby、Python等都屬于動態語言;C、C++不屬于動態語言。從反射的角度來說,Java屬于半動態語言。
2.3.2 反射機制的概念
反射機制指在程序運行過程中,對任意一個類都能獲取其所有屬性和方法,并且對任意一個對象都能調用其任意一個方法。這種動態獲取類和對象的信息,以及動態調用對象的方法的功能被稱為Java語言的反射機制。
2.3.3 反射的應用
Java中的對象有兩種類型:編譯時類型和運行時類型。編譯時類型指在聲明對象時所采用的類型,運行時類型指為對象賦值時所采用的類型。
在如下代碼中,persion對象的編譯時類型為Person,運行時類型為Student,因此無法在編譯時獲取在Student類中定義的方法:
Person persion = new Student();
因此,程序在編譯期間無法預知該對象和類的真實信息,只能通過運行時信息來發現該對象和類的真實信息,而其真實信息(對象的屬性和方法)通常通過反射機制來獲取,這便是Java語言中反射機制的核心功能。
2.3.4 Java的反射API
Java的反射API主要用于在運行過程中動態生成類、接口或對象等信息,其常用API如下。
◎ Class類:用于獲取類的屬性、方法等信息。
◎ Field類:表示類的成員變量,用于獲取和設置類中的屬性值。
◎ Method類:表示類的方法,用于獲取方法的描述信息或者執行某個方法。
◎ Constructor類:表示類的構造方法。
2.3.5 反射的步驟
反射的步驟如下。
(1)獲取想要操作的類的Class對象,該Class對象是反射的核心,通過它可以調用類的任意方法。
(2)調用Class對象所對應的類中定義的方法,這是反射的使用階段。
(3)使用反射API來獲取并調用類的屬性和方法等信息。
獲取Class對象的3種方法如下。
(1)調用某個對象的getClass方法以獲取該類對應的Class對象:
Person p = new Person(); Class clazz = p.getClass();
(2)調用某個類的class屬性以獲取該類對應的Class對象:
Class clazz = Person.class;
(3)調用Class類中的forName靜態方法以獲取該類對應的Class對象,這是最安全、性能也最好的方法:
Class clazz=Class.forName("fullClassPath"); //fullClassPath為類的包路徑及名稱
我們在獲得想要操作的類的Class對象后,可以通過Class類中的方法獲取并查看該類中的方法和屬性,具體代碼如下:
//1:獲取Person類的Class對象 Class clazz = Class.forName("hello.java.reflect.Persion"); //2:獲取Person類的所有方法的信息 Method[] method = clazz.getDeclaredMethods(); for(Method m:method){ System.out.println(m.toString()); } //3:獲取Person類的所有成員的屬性信息 Field[] field = clazz.getDeclaredFields(); for(Field f:field){ System.out.println(f.toString()); } //4:獲取Person類的所有構造方法的信息 Constructor[] constructor = clazz.getDeclaredConstructors(); for(Constructor c:constructor){ System.out.println(c.toString()); }
2.3.6 創建對象的兩種方式
創建對象的兩種方式如下。
◎ 使用Class對象的newInstance方法創建該Class對象對應類的實例,這種方法要求該Class對象對應的類有默認的空構造器。
◎ 先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance方法創建Class對象對應類的實例,通過這種方法可以選定構造方法創建實例。
創建對象的具體代碼如下:
//1.1:獲取Person類的Class對象 Class clazz = Class.forName("hello.java.reflect.Persion"); //2.1:使用newInstane方法創建對象 Person p = (Person) clazz.newInstance(); //1.2:獲取構造方法并創建對象 Constructor c = clazz.getDeclaredConstructor (String.class, String.class, int.class); //2.2:根據構造方法創建對象并設置屬性 Person p1 = (Person) c.newInstance("李四", "男",20);
2.3.7 Method的invoke方法
Method提供了關于類或接口上某個方法及如何訪問該方法的信息,那么在運行的代碼中如何動態調用該方法呢?答案就通過調用Method的invoke方法。我們通過invoke方法可以實現動態調用,比如可以動態傳入參數及將方法參數化。具體過程為:獲取對象的Method,并調用Method的invoke方法,如下所述。
(1)獲取Method對象:通過調用Class對象的getMethod(String name, Class<? >... parameterTypes)返回一個Method對象,它描述了此Class對象所表示的類或接口指定的公共成員方法。name參數是String類型,用于指定所需方法的名稱。parameterTypes參數是按聲明順序標識該方法的形參類型的Class對象的一個數組,如果parameterTypes為null,則按空數組處理。
(2)調用invoke方法:指通過調用Method對象的invoke方法來動態執行函數。invoke方法的具體使用代碼如下:
//step 1:獲取Persion類(hello.java.reflect.Persion)的Class對象 Class clz = Class.forName("hello.java.reflect.Persion"); //step 2:獲取Class對象中的setName方法 Method method = clz.getMethod("setName", String.class); //step 3:獲取Constructor對象 Constructor constructor = clz.getConstructor(); //step 4:根據Constructor定義對象 Object object = constructor.newInstance(); // //step 5:調用method的invoke方法,這里的method表示setName方法 //因此,相當于動態調用object對象的setName方法并傳入alex參數 method.invoke(object, "alex");
以上代碼首先通過Class.forName方法獲取Persion類的Class對象;然后調用Persion類的Class對象的getMethod("setName", String.class)獲取一個method對象;接著使用Class對象獲取指定的Constructor對象并調用Constructor對象的newInstance方法創建Class對象對應類的實例;最后通過調用method.invoke方法實現動態調用,這樣就通過反射動態生成類的對象并調用其方法。
- Facebook Application Development with Graph API Cookbook
- 案例式C語言程序設計
- 企業級Java EE架構設計精深實踐
- Mastering Objectoriented Python
- arc42 by Example
- jQuery從入門到精通 (軟件開發視頻大講堂)
- C語言實驗指導及習題解析
- Node.js開發指南
- Spring Boot+MVC實戰指南
- Extending Unity with Editor Scripting
- RESTful Web Clients:基于超媒體的可復用客戶端
- 大學計算機基礎實訓教程
- 計算語言學導論
- Java程序設計實用教程(第2版)
- Python物理建模初學者指南(第2版)