背景:
我不相信你會問—啥是框架? (簡單理解爲可複用的代碼)像現在很流行的框架如 Spring , Spring boot,Spring AOC 等都是框架,組成它們的代碼中總會見到反射機制。
簡介:
反射: 將類的組成部分封裝成一個對象。
用一張圖解釋哈:
過程解釋:
還是一個老生常談的問題,我們用高級語言編寫的代碼如何被計算機執行? 都知道計算機只能執行機器碼。 所以我們編譯高級語言代碼最終也會生成機器碼,只不過中間有一個過度的部分那就是字節碼。利用 javac 生成字節碼後,我們想執行這個程序。又知道計算機是從內存中讀取指令和數據的,我們利用反射將字節碼文件加載進內存,然後被計算機所執行。
使用反射的好處:
1 可以在程序運行中操縱這些對象
2 可以解耦,提高程序的可擴展性
===============================================================
應用舉例:
獲取 Class 對象的方式(可以理解 Class 對象是反射的另一種體現):
1 Class.forName("全類名") // 將磁盤中的對應代碼加載進內存,返回 Class 對象(**多用於配製文件)
2 類名.class //通過類名的屬性獲取對象(內存中),(**多用於參數傳遞)
3 對象.getclass() // getclass()在Object對象中定義着(**多用於對象獲取字節碼的方式)
//結論
同一個字節碼文件(*.class)在一次程序運行中只會被加載一次進內存,不論通過那種方式獲取 Class 都是代指同一個對象
Class 對象的功能:
// 獲取內存中的成員變量們
- cls.getFileds(); // 獲取 public 修飾的成員變量
- cls.getFiled(String name); // 獲取指定 public 修飾的成員變量
- cls.getDeclaredFileds(); // 獲取全部成員變量(忽略修飾符)
- cls.getDeclaredFiled(String name); // 獲取指定成員變量(忽略修飾符)
注:獲取 private 修飾的變量後想給其賦值必須先執行能忽略修飾符的代碼-->
- cls.setAccessible(True);
// 獲取內存中的構造方法們
- cls.getConstructor(String.class,int.class); // 獲取指定 public 修飾的構造方法
- cls.getConstructors(); // 獲取 public 修飾的構造方法
- cls.getDeclaredConstructor(String.class,int.class);// 獲取指定 public 修飾的構造方法(忽略修飾符)
- cls.getDeclaredConstructors(); // // 獲取構造方法(忽略修飾符)
獲取構造方法有啥用呢??? 哈哈,當然是創建對象啦。
Constructor c = cls.getConstructor(String.class,int.class);
Object o = c.newInstance("ss",70);
// 獲取成員方法也是相似的代碼(這裏就忽略了)
我想看到這裏你還是對反射的作用記憶不深刻,也不知道用它來獲取對象和獲取對應的方法並執行有啥用? 如果你有這個疑問,那麼問題就來了:
問: 利用反射機制,寫一個框架,可以創建任意對象,執行任意方法。
是不是沒有思路??? 是不是覺得雖然知道反射但還是不會用它解決問題?如果你一上來就寫代碼,根據傳入指定的全類名和方法名這種辦法,可行是可行但耦合度太高了。
簡單的處理是 配製文件+反射(在配置文件內寫全類名,和指定要執行的方法名。)
/**
- 創建配置文件(後綴名一定爲 .properties)
- 創建配置文件對象
- 獲取配置文件
- 根據配置文件對象獲取配置文件內容
- 根據內容創建對象
- 根據內容找到方法並執行
**/
Properties pro = new Properties();
//獲取配置文件
InputStream in = getclass.getClassLoad().getResourceAsStream("配置文件路徑")
//加載配置文件
pro.load(in);
//獲取配置文件內的內容
String className = pro.getProperty("className");
String method_name = pro.getProperty("method_name");
//利用反射創建對象,執行對應方法
Class cls = class.forNmae("className"); // 加載對象進內存
Object obj = cls.newInstance(); //創建對象
Method me = cls.getMethod("method_name"); //獲取指定方法
me.invoke(obj); //執行指定方法(需要對象爲形參)
總結:
上面寫到了一些反射的常見用法,以及在框架中如何使用反射機制,極大的簡化了代碼量。我希望對你有所幫助。