其實就是動態加載一個指定的類,並獲取該類中的全部的內容。 並且將字節碼文件封裝成對象,並將字節碼文件中的內容都封裝成對象,這樣便於操做這些成員。 簡單說:反射技術能夠對一個類進行解剖。
反射的好處:java
大大的加強了程序的擴展性。
反射的基本步驟:函數
得到Class對象,就是獲取到指定的名稱的字節碼文件對象。 實例化對象,得到類的屬性、方法或構造函數。 訪問屬性、調用方法、調用構造函數建立對象。
獲取這個Class對象,有三種方式:code
1:經過每一個對象都具有的方法getClass來獲取。弊端:必需要建立該類對象,才能夠調用getClass方法。 2:每個數據類型(基本數據類型和引用數據類型)都有一個靜態的屬性class。弊端:必需要先明確該類。 前兩種方式不利於程序的擴展,由於都須要在程序使用具體的類來完成。 3:使用的Class類中的方法,靜態的forName方法。 指定什麼類名,就獲取什麼類字節碼文件對象,這種方式的擴展性最強,只要將類名的字符串傳入便可。 // 1. 根據給定的類名來得到 用於類加載 String classname = "cn.itcast.reflect.Person";// 來自配置文件 Class clazz = Class.forName(classname);// 此對象表明Person.class // 2. 若是拿到了對象,不知道是什麼類型 用於得到對象的類型 Object obj = new Person(); Class clazz1 = obj.getClass();// 得到對象具體的類型 // 3. 若是是明確地得到某個類的Class對象 主要用於傳參 Class clazz2 = Person.class;
//須要得到java類的各個組成部分,首先須要得到類的Class對象,得到Class對象的三種方式: Class.forName(classname)用於作類加載 obj.getClass()用於得到對象的類型 類名.class 用於得到指定的類型,傳參用 //反射類的成員方法: Class clazz = Person.class; Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2}); method.invoke(); //反射類的構造函數: Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...}) con.newInstance(params...) //反射類的屬性: Field field = clazz.getField(fieldName); field.setAccessible(true); field.setObject(value);
獲取了字節碼文件對象後,最終都須要建立指定類的對象:對象
建立對象的兩種方式(其實就是對象在進行實例化時的初始化方式): 調用空參數的構造函數:使用了Class類中的newInstance()方法。 調用帶參數的構造函數:先要獲取指定參數列表的構造函數對象, 而後經過該構造函數的對象的newInstance(實際參數) 進行對象的初始化。
綜上所述,第二種方式,必需要先明確具體的構造函數的參數類型,不便於擴展。
因此通常狀況下,被反射的類,內部一般都會提供一個公有的空參數的構造函數。字符串
// 如何生成獲取到字節碼文件對象的實例對象。 Class clazz = Class.forName("cn.itcast.bean.Person");//類加載 // 直接得到指定的類型 clazz = Person.class; // 根據對象得到類型 Object obj = new Person("zhangsan", 19); clazz = obj.getClass(); Object obj = clazz.newInstance();//該實例化對象的方法調用就是指定類中的空參數構造函數,給建立對象進行初始化。當指定類中沒有空參數構造函數時,該如何建立該類對象呢?請看method_2(); public static void method_2() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); //既然類中沒有空參數的構造函數,那麼只有獲取指定參數的構造函數,用該函數來進行實例化。 //獲取一個帶參數的構造器。 Constructor constructor = clazz.getConstructor(String.class,int.class); //想要對對象進行初始化,使用構造器的方法newInstance(); Object obj = constructor.newInstance("zhagnsan",30); //獲取全部構造器。 Constructor[] constructors = clazz.getConstructors();//只包含公共的 constructors = clazz.getDeclaredConstructors();//包含私有的 for(Constructor con : constructors) { System.out.println(con); } }
//獲取類中全部的方法。 public static void method_1() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method[] methods = clazz.getMethods();//獲取的是該類中的公有方法和父類中的公有方法。 methods = clazz.getDeclaredMethods();//獲取本類中的方法,包含私有方法。 for(Method method : methods) { System.out.println(method); } } //獲取指定方法; public static void method_2() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); //獲取指定名稱的方法。 Method method = clazz.getMethod("show", int.class,String.class); //想要運行指定方法,固然是方法對象最清楚,爲了讓方法運行,調用方法對象的invoke方法便可,可是方法運行必需要明確所屬的對象和具體的實際參數。 Object obj = clazz.newInstance(); method.invoke(obj, 39,"hehehe");//執行一個方法 } //想要運行私有方法。 public static void method_3() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); //想要獲取私有方法。必須用getDeclearMethod(); Method method = clazz.getDeclaredMethod("method", null); // 私有方法不能直接訪問,由於權限不夠。非要訪問,能夠經過暴力的方式。 method.setAccessible(true);//通常不多用,由於私有就是隱藏起來,因此儘可能不要訪問。 } //反射靜態方法。 public static void method_4() throws Exception { Class clazz = Class.forName("cn.itcast.bean.Person"); Method method = clazz.getMethod("function",null); method.invoke(null,null); }