一、java的反射
java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取信息以及動態
調用對象的方法的功能成爲java語言的反射機制。
java的反射機制主要提供了以下功能:
• 在運行時判斷任意一個對象所屬的類;
• 在運行時構造任意一個類的對象;
• 在運行時判斷任意一個類所具有的成員變量和方法;
• 在運行時調用任意一個對象的方法;
• 生成動態代理。
1、JVM創建Class類對象的過程
2、獲取class的三種方式
- Class.forName(“com.weige.Test”);
- Test.class;
- new Test().getClass();
3、反射的作用
Java中編譯類型有兩種
靜態編譯:在編譯時確定類型,綁定對象即通過
動態編譯:運行時確定類型,綁定對象
反射允許靜態語言在運行時檢查、修改程序的結構與行爲。 在靜態語言中,使用一個變量時,必須知道它的類型;在Java中,變量的類型信息在編譯時都保存到了class文件中,這樣在運行時才能保證準確無誤。換句話說,程序在運行時的行爲都是固定的。如果想在運行時改變,就需要Java的反射機制。
動態編譯最大限度地發揮了Java的靈活性,體現了多態的應用,可以減低類之間的耦合性。 Java反射是Java被視爲動態(或準動態)語言的一個關鍵性質。
4、反射的應用場景
- 最重要的用途就是開發各種通用框架,注入屬性,調用方法,如Spring
- JDBC中,利用反射動態加載了數據庫驅動程序
- Web服務器中利用反射調用了Sevlet的服務方法
- Eclispe等開發工具利用反射動態刨析對象的類型與結構,動態提示對象的屬性和方法
5、反射機制的優缺點?
- 優點:可以動態執行,在運行期間根據業務功能動態執行方法、訪問屬性,最大限度發揮了java的靈活性。
- 缺點:對性能有影響,這類操作總是慢於直接執行java代碼。
A、反射實例——通過屬性調用對象
public static void main(String[] args) throws Exception{ Class<?> a = new Test().getClass(); Test test = new Test("456"); Field field= a.getDeclaredField("age"); field.set(test, "123"); System.out.println(field.get(test)); }
B、反射實例——通過方法調用對象
public static void main(String[] args) throws Exception{ Class<?> a = new Test().getClass(); Method method = a.getDeclaredMethod("say", String.class,int.class); method.invoke(a.newInstance(), "asd",1); } private static void say(String a,int b) { System.out.println("測試"+a+b); }
二、函數的回調
在Java裏面,我們使用接口來實現回調。回調函數,或簡稱回調,是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計允許了底層代碼調用在高層定義的子程序。
程序員A寫了一段程序(程序a),其中預留有回調函數接口,並封裝好了該程序。程序員B要讓a調用自己的程序b中的一個方法,於是,他通過a中的接口回調自己b中的方法。目的達到。在C/C++中,要用回調函數,被掉函數需要告訴調用者自己的指針地址,但在JAVA中沒有指針,怎麼辦?我們可以通過接口(interface)來實現定義回調函數。
假設我是程序員A,以下是我的程序a:
public class Caller { public MyCallInterface mc; public void setCallfuc(MyCallInterface mc) { this.mc= mc; } public void call(){ this.mc.method(); } }
我還需要定義一個接口,以便程序員B根據我的定義編寫程序實現接口。
public interface MyCallInterface { public void method(); }
於是,程序員B只需要實現這個接口就能達到回調的目的了:
public class B implements MyCallInterface { public void method() { System.out.println("回調"); } public static void main(String args[]) { Caller call = new Caller(); call.setCallfuc(new B()); call.call(); } }
主要就是回調者需要實現一個回調接口,然後把自己,也就是相當於接口當做參數傳給別人,別人拿到這個接口之後,最終都會調用接口中的方法,就相當於執行了回調方法。
下面舉個通俗的例子:
某天,我打電話向你請教問題,當然是個難題你一時想不出解決方法,我又不能拿着電話在那裏傻等,於是我們約定:等你想出辦法後打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該如此這般處理。故事到此結束。這個例子說明了“異步+回調”的編程模式。其中,你後來打手機告訴我結果便是一個“回調”過程;我的手機號碼必須在以前告訴你,這便是註冊回調函數;我的手機號碼應該有效並且手機能夠接收到你的呼叫,這是回調函數必須符合接口規範。
參考:
https://blog.csdn.net/qq_30346471/article/details/84299993
https://blog.csdn.net/weixin_45864705/article/details/126271798