反射機制
基本概念:
Java反射機制就是在程序在運行狀態中,對任意一個類(class文件,也就是字節碼文件),都能知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態的調用對象的方法的功能我們稱之爲反射機制。
理解: 從字面的意思來看,反射,就是某一個東西照鏡子,從而看到自己的樣子,而在java裏這個被反射的東西就是類,類通過反射我們可以得到類裏面的方法和屬性。 反射有什麼用呢?在我們的java程序運行之後是不能通過改變它的源代碼從而改變它的運行狀態,現在反射就起了作用,java程序員在編寫程序之初就會留下一些接口,寫一些配置文件,我們就可以寫一些新的類去實現這些接口,再修改配置文件,這樣子程序就會通過反射的方式讀取到這些類,從而動態的獲取加載類裏面的方法和屬性!
如何去反射:
1、獲得Class對象,就是獲取到指定的名稱的字節碼文件對象。
2、實例化對象,獲得類的屬性、方法或構造函數。
3、訪問屬性、調用方法、調用構造函數創建對象。
如何獲取Class對象
1:通過每個對象都具備的方法getClass來獲取。弊端:必須要創建該類對象,纔可以調用getClass方法。
// 如果拿到了對象,不知道是什麼類型,用於獲得對象的類型
Object obj = new Person();
Class clazz1 = obj.getClass();// 獲得對象具體的類型
2:每一個數據類型(基本數據類型和引用數據類型)都有一個靜態的屬性class。弊端:必須要先明確該類。
// 如果是明確地獲得某個類的Class對象 主要用於傳參
Class clazz2 = Person.class;
前兩種方式不利於程序的擴展,因爲都需要在程序使用具體的類來完成。
3:使用的Class類中的方法,靜態的forName方法。
指定什麼類名,就獲取什麼類字節碼文件對象,這種方式的擴展性最強,只要將類名的字符串傳入即可。
// 根據給定的類名來獲得 用於類加載
String classname = "cn.itcast.reflect.Person";// 來自配置文件
Class clazz = Class.forName(classname);// 此對象代表Person.class
反射的用法:
1)、反射類的構造函數:
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);//這裏恐怕不一定對
//按照API 1.6,如果對象是Person的話,應該傳入new Person("zhagnsan",30)
//獲取所有構造器。
Constructor[] constructors = clazz.getConstructors();//只包含公共的
constructors = clazz.getDeclaredConstructors();//包含私有的
for(Constructor con : constructors) {
System.out.println(con);
}
}
2)、反射類的成員方法:
//獲取類中所有的方法。
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);
}
3)、反射類的屬性:
Class clazz = Person.class;//獲取Class對象
Field field = clazz.getField(fieldName);//獲取屬性
field.setAccessible(true);//獲得更改權限
field.setObject(value);//更改屬性值
反射的總結:反射大大的增強了程序的擴展性。
把每個個體具體對象的共同屬性和方法抽取出就可以封裝成人的類;把java類中的共同屬性和方法封裝起來就是一個Class類,每個類都具備的東西,也就是字段,構造函數,一般函數!通過Class這個類就可以去獲取想要的每個類的字段,構造函數,一般函數!