序言java
通常而言,動態語言是指程序運行時,容許改變程序結構或變量類型的語言。git
從這個觀點來看,Perl、Python、Ruby是動態語言,C++、Java、C#不是動態語言。github
可是Java有動態相關機制:Reflection,反射,是指能夠運行時加載、探知、使用編譯期間徹底未知的Classes。編程
1、什麼是反射?數組
Java程序能夠加載一個運行時才得知名稱的Class,獲取其完整構造,並生成其對象實體,設置屬性,調用方法。安全
這種動態獲取類信息以及動態調用對象方法的功能就是Java語言的反射機制。測試
2、反射的做用?ui
一、在運行時判斷任意一個對象所屬的類this
二、在運行時構造任意一個類的對象編碼
三、在運行時判斷任意一個類所具備的成員變量和方法
四、在運行時調用任意一個對象的方法
3、反射的一些概念
一、反射相關的類和接口,都放在軟件包java.lang.reflect
軟件包java.lang.reflect提供類和接口,以獲取關於類和對象的反射信息。
在安全限制內,反射容許編程訪問關於加載類的字段、方法和構造方法的信息,並容許使用反射字段、方法和構造方法對對象上的基本對等項進行操做。
若是必需的 ReflectPermission 可用,則 AccessibleObject 容許抑制訪問檢查。Array 提供動態建立和訪問數組的靜態方法。
此包中的類以及 java.lang.Class 能夠適應如下應用程序的須要:調試程序、解釋程序、對象檢查程序、類瀏覽程序等。
二、反射相關類摘要
類名 | 說明 |
AccessibleObject | AccessibleObject 類是Field、Method 和 Constructor 對象的基類。 |
Constructor<T> | Constructor提供關於類的單個構造方法的信息以及對它的訪問權限。 |
Field | Field提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。 |
Method | Method提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息。 |
Modifier | Modifier類提供了static方法和常量,對類和成員訪問修飾符進行解碼。 |
Proxy | Proxy提供用於建立動態代理類和實例的靜態方法,它仍是由這些方法創 建的全部動態代理類的超類。 |
ReflectPermission | 反射操做的Permission類。 |
三、java.lang.Class說明
Class 類和通常類同樣繼承自 Object ,其實體用以表達 Java 程序運行時的類和接口,枚舉,數組,基礎類型(boolean, byte, char, short, int, long, float, double)以及關鍵詞void。
Class 沒有公共構造方法。當一個 Class 被加載,或當加載器(class loader)的 defineClass() 被 JVM 調用, JVM 便自動產生一個類對象 。
Java 有個 Object 類,是全部 Java 類的繼承根源,其內聲明瞭數個應該在全部 Java 類中被改寫的方法: hashCode()、equals()、clone() 、toString() 、getClass() 等。
其中 getClass() 返回一個 Class 類的對象,所以對於任意一個 Java 對象,均可以經過此方法得到對象的類型。
===Class 類是 Reflection API 中的核心類,它有如下方法===
getName() :得到類的完整名字。
getFields() :得到類的 public 類型的屬性。
getDeclaredFields() :得到類的全部屬性。
getMethods() :得到類的 public 類型的方法。
getDeclaredMethods() :得到類的全部方法。
getMethod(String name, Class[] parameterTypes) :得到類的特定方法, name 參數指定方法的名字, parameterTypes 參數指定方法的參數類型。
getConstructors() :得到類的 public 類型的構造方法。
getConstructor(Class[] parameterTypes) :得到類的特定構造方法, parameterTypes 參數指定構造方法的參數類型。
newInstance() :經過類的不帶參數的構造方法建立這個類的一個對象。
4、反射的具體實現
反射用到的測試類:含測試用的方法和屬性
package code.lemon; import java.util.Map; import java.util.Set; import java.util.List; public class Pear{ Map<String, String> map; public Set<String> set; public Class<?> clazz; String str; Set set1; public List<String> list; private static Pear pear; static{ pear = new Pear(); } private Pear(){ } public Pear(String str){ this.str = str; } public static void main(String [] args){ System.out.println(Pear.class.getPackage()); } public String getStr(){ return str; } private void setStr(String str){ this.str = str; } }
一、獲取類的構造方法
public static void printConstructor(String className) { try { Class<?> clazz = Class.forName(className); //返回一個包含某些 Constructor 對象的數組, //這些對象反映此 Class 對象所表示的類的全部公共構造方法。 Constructor<?>[] constructors = clazz.getConstructors(); for (int i = 0; i < constructors.length; i++) { System.out.println(constructors[i]); } System.out.println("------------------"); //返回 Constructor 對象的一個數組, //這些對象反映此 Class 對象表示的類聲明的全部構造方法。 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); for (int i = 0; i < declaredConstructors.length; i++) { //返回此類或接口以整數編碼的 Java 語言修飾符。 int modifiers = declaredConstructors[i].getModifiers(); System.out.println(declaredConstructors[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
二、獲取類屬性
public static void printField(String className) { try { Class<?> clazz = Class.forName(className); //返回一個包含某些 Field 對象的數組, //這些對象反映此 Class 對象所表示的類或接口的全部可訪問公共字段。 Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { System.out.println(fields[i]); } System.out.println("------------------"); //返回 Field 對象的一個數組, //這些對象反映此 Class 對象所表示的類或接口所聲明的全部字段, //包括公共、保護、默認(包)訪問和私有字段,但不包括繼承的字段。 Field[] declaredFields = clazz.getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { int modifiers = declaredFields[i].getModifiers(); System.out.println(declaredFields[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
三、獲取類方法
public static void printMethod(String className) { try { Class<?> clazz = Class.forName(className); //返回一個包含某些 Method 對象的數組, //這些對象反映此 Class 對象所表示的類或接口 //包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口的公共方法。 Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { System.out.println(methods[i]); } System.out.println("------------------"); //返回 Method 對象的一個數組, //這些對象反映此 Class 對象表示的類或接口聲明的全部方法, //包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 Method[] declaredMethods = clazz.getDeclaredMethods(); for (int i = 0; i < declaredMethods.length; i++) { int modifiers = declaredMethods[i].getModifiers(); System.out.println(declaredMethods[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
四、私有方法的調用
public static void invokeMethod(String className) { try { Class<?> clazz = Class.forName(className); //Pear pear = new Pear("hello"); Object pear = clazz.getConstructor(new Class[]{}).newInstance(new Object[]{}); //返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 //name 參數是一個 String,它指定所需方法的簡稱, //parameterTypes 參數是 Class 對象的一個數組,它按聲明順序標識該方法的形式參數類型。 Method declaredMethod = clazz.getDeclaredMethod("setStr", new Class[]{String.class}); //對全部屬性設置訪問權限 當類中的成員變量爲private時 必須設置此項 declaredMethod.setAccessible(true); //對帶有指定參數的指定對象調用由此 Method 對象表示的基礎方法。 declaredMethod.invoke(pear, new Object[]{"world"}); Method declaredMethod1 = clazz.getDeclaredMethod("getStr", new Class[]{}); Object result = declaredMethod1.invoke(pear, new Object[]{}); System.out.println((String)result); } catch (Exception e) { } }
五、動態建立、訪問數組
public static void printArray() { try{ Class <?> classType = Class.forName("java.lang.String"); //newInstance建立此 Class 對象所表示的類的一個新實例。 Object array = Array.newInstance(classType, 10); Array.set(array, 5, "hello"); for(int i =0;i < Array.getLength(array);i ++){ String str = (String)Array.get(array,i); System.out.println(str); } }catch(Exception e){ } }
本例的包名爲code.lemon,參數className爲"code.lemon.Pear"
5、具體代碼以下