---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------
反射
Java程序中的各個Java類屬於同一類事物,描述這類事物的Java類名就是Class
對比提問:衆多的人用一個什麼類表示?衆多的Java類用一個什麼類表示?
人 Person java類 Class
對比提問:Person類代表人,它的實例對象就是張三,李四這樣一個個具體的人,Class類代表Java類,它的各個事例對象又分別對應 什麼呢?
對應各個類的字節碼,如Person類的字節碼,ArrayList類的字節碼等等
一個類被類加載器加載進入內存中,佔用了一片存儲空間,這個空間裏面的內容就是類的字節碼,不同的類的字節碼不同,所以它們在內存 中的內容是不同的
這一個個空間可分別用一個個的對象來表示,這些對象顯然具有相同的類型。
如何得到各個字節碼對象的事例對象(Class類型)
1、類名.class,如:System.class
2、對象.getClass(),如:new Date().getClass()
3、Class.forName("類名"); ,如:Class.forName("java.lang.String");
九個預定義Class實例對象:
八個基本數據類型(boolean,char,byte,short,int,lang,float,double)
數組類型的Class實例對象:
class.isArray()
總之,只要在源程序中出現的類型,都有各自的Class實例對象,如:int[],void
如:
- package cn.itcast.day1;
- public class ReflectTest {
- /**
- * @param args
- */
- public static void main(String[] args)throws Exception {
- // TODO Auto-generated method stub
- String str1 = "abc";
- Class cla1 = str1.getClass();
- Class cla2 = String.class;
- Class cla3 = Class.forName("java.lang.String");
- //驗證三種方法是不是同一份字節碼,答案都是true
- System.out.println(cla1==cla2);
- System.out.println(cla1==cla3);
- System.out.println(cla1.isPrimitive());//判斷是否是一個基本數據類型
- System.out.println(int.class==Integer.class);//int和Integer是不同類型,各自有自己的字節碼
- System.out.println(int.class==Integer.TYPE);//TYPE用來表示所包裝的那份基本類型的字節碼
- //數組出現的類型也有自己的字節碼,用isArray()判斷
- System.out.println(int[].class.isPrimitive());
- System.out.println(int[].class.isArray());
- }
- }
反射概念:就是把JAVA類中的各種成分映射成相應的JAVA類。
如:一個java類中用一個Class類的對象來表示,一個類中的組成部分:成員變量,方法,構造方法,包等等信息也用一個個的JAVA類來表示,就像汽車是一個類,汽車的發動機,變速箱等等也是一個個類。表示java類的Class類顯然就是提供一系列方法,來獲得其中的變量,方法和構造方 法,修飾符,包等等信息,這個信息就是用相應類的事例對象來表示,它們是Field、Method、Constructor、Package等等。
Constructor類:
1、概述:Constructor代表某個類的構造方法。
2、獲取構造方法:
1、如何得到某個類的所有構造方法(如得到String類的所有構造方法):
Constructor[] cons = Class.forName(“java.lang.String”).getConstructors();
2、獲取某一個構造方法:
Constructor con =String.class.getConstructor(StringBuffer.class); ①
3、創建實例對象:
1、通常方式:String str = new String(new StringBuffer (”abc”));
2、反射方式:String str = (String)con.newInstance(new StringBuffer(“abc”)); ②
調用獲得的方法時要用到上面相同類型的實例對象,即兩個StringBuffer()要對應相等。
NewInstance():構造出一個實例對象,每調用一次就構造一個對象。
注意:上面的兩個地方①②都要用到StringBuffer,這必須是一致的。
第①個是指定要帶StringBuffer參數類型的構造方法,即所需使用的是含StringBuffer類型的構造方法。
第②個是用這個構造方法創建對象,要傳入的參數類型必須是StringBuffer。
4、Class.newInstance():創建一個對象,不帶參數的構造方法。
Field類:
概述:Field類代表成員變量(字段)的反射。
如:
- public class ReflectPoint {
- private int x;
- public int y;
- public String toString(){
- return str1+";" + str2 + ";" + str3;
- }
- }
- public class FieldTest(){
- ReflectPoint pt1 = new ReflectPoint(3,5);
- //fieldX和fieldY並不是對象身上的變量,而是類上的
- //要用它去取某個對象上的對應的值,傳入什麼對象,就取相應對象的值。
- Field fieldY = pt1.getClass().getField("y");
- System.out.println(fieldY.get(pt1));
- //獲取私有的成員變量
- Field fieldX = pt1.getClass().getDeclaredField("x");
- fieldX.setAccessible(true);
- System.out.println(fieldX.get(pt1));
- }
Method類:
1、概述:Method類代表某個類中的一個成員方法。調用某個對象身上的方法,要先得到方法,再針對某個對象調用。
2、專家模式:誰調用這個數據,就是誰在調用它的專家。
如人關門。調用者:是門調用管的動作,對象是門,因爲門知道如何執行關的動作,通過門軸之類的細節實現。指揮者:是人在指揮門做 關的動作,只是給門發出了關的信號,讓門執行。
總結:變量使用方法,是方法本身知道如何實現執行的過程,也就是“方法對象”調用方法,才執行了方法的每個細節的。
3、獲取某個類中的某個方法:(如String str = ”abc”)
1、通常方式:str.charAt(1)
2、反射方式:
Method charAtMethod = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
charAtMethod.invoke(str,1);
說明:如果傳遞給Method對象的invoke()方法的第一個參數爲null,說明Method對象對應的是一個靜態方法
4、用反射方式執行某個main方法:
首先要明確爲何要用反射:在寫源程序時,並不知道使用者傳入的類名是什麼,但是雖然傳入的類名不知道,而知道的是這個類中 的方法有main這個方法,所以可以通過反射的方式,通過使用者傳入的類名(可定義字符串型變量作爲傳入類名的入口,通過這個 變量代表類名),內部通過傳入的類名獲取其main方法,然後執行相應的內容。
如:
- //Method類演示
- private static void methodTest(String [] args) throws Exception {
- String str1 = "abc";
- //一般方法:
- System.out.println(str1.charAt(1));
- //反射方法 :
- Method methodCharAt =
- Class.forName("java.lang.String").getMethod("charAt",int.class);
- System.out.println(methodCharAt.invoke(str1,1));
- //用反射方式執行某個main方法
- //一般方式:
- Test.main(new String[]{"111","222","333"});
- System.out.println("-------");
- //反射方式:
- String startingClassName = args[0];
- Method methodMain =
- Class.forName(startingClassName).getMethod("main",String[].class);
- //方案一:強制轉換爲超類Object,不用拆包
- methodMain.invoke(null,(Object)new String[]{"111","222","333"});
- //方案二:將數組打包,編譯器拆包後就是一個String[]類型的整體
- methodMain.invoke(null,new Object[]{new String[]{"111","222","333"}});
- }
- //定義一個測試類
- class Test{
- public static void main(String [] args){
- for(String arg : args){
- System.out.println(arg);
- }
- }
- }
數組的反射:
具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象(此處比較與值無關)。
代表數組的Class實例對象的getSuperClass()方法返回的父類爲Object類對應的Class。
基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用;非基本類型的一維數組,既可以當做Object類型使用,又 可以當做Object[]類型使用。
Arrays.asList()方法處理int[]和String[]時的差異。
Array工具類用於完成對數組的反射操作。
---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ----------------------