Java回呼函數理解和應用
所謂回調:就是A類中調用B類中的某個方法C,然後B類中反過來調用A類中的方法D,D這個方法就叫回調方法,這樣子說你是不是有點暈暈的。
在未理解之前,我也是一臉懵逼,等我理解之後,發現和Javascript的回呼函數原理基本是一樣,一個是將對象作為參數傳遞,一個是將函數作為參數傳遞。
從維基百科上面摘抄定義:
在電腦程式設計中,回呼函數,或簡稱回調,是指通過函數參數傳遞到其它代碼的,某一塊可執行代碼的引用。這一設計允許了底層代碼調用在高層定義的子程式。
舉個例子有個程式員和一個專案經理,XX專案經理向程式員安排任務讓程式員去完成,程式員獲得任務並記下是XX專案經理安排的任務,程式員將任務完成後,擷取通知XX專案經理的方式,發送一條語音總機專案經理任務已經完成。
下面上執行個體:
建立一個專案經理類:
public class ProjectManager { private String name; public ProjectManager(String name) { this.name =name; } public String getName() { return this.name; } /** * 通知方法 * @param msg */ public void noticeMe(String msg) { System.err.println(msg); } /** * 安排任務 * @param task */ public void arrange(String task) { //安排程式員幹活 new Programmer().receiveTask(task, this); } public void doOtherWork() { System.err.println("專案經理幹其他事情..."); }}
建立一個程式員類:
import java.util.concurrent.TimeUnit;public class Programmer { //記下是XX專案經理,而不是其他專案經理 ProjectManager manager; /**程式員接受任務*/ public void receiveTask(String task,ProjectManager manager) { this.manager = manager; try { //程式員開始執行任務 this.excuteTask(task); } catch (InterruptedException e) { e.printStackTrace(); } } /**執行任務*/ private void excuteTask(String task) throws InterruptedException { System.err.println("執行專案經理:"+manager.getName()+"安排的任務-->"+task); //任務執行中 TimeUnit.SECONDS.sleep(1); //任務完成 this.finished(task); } /**任務完成*/ public void finished(String task) { //擷取通知專案經理的方法,並發出通知 //進行函數回調,這裡還不算真正的回調 manager.noticeMe(manager.getName()+"你好,你安排的任務"+task+"已經完成。"); }}
建立測試類別:
public class CallbackTest { /** * @param args */ public static void main(String[] args) { ProjectManager prjMgr = new ProjectManager("王響"); prjMgr.arrange("今晚完成資料庫設計..."); prjMgr.doOtherWork(); }}
運行結果:
但實際上,專案經理可能有好多個連絡方式,有些方式可能是無效的。那我怎樣才能知道哪個才是真確的通知方式呢。那就需要專案經理指定哪個方式是正確的,這樣程式員也只要記住連絡方式即可。在C/C++中,要用回呼函數,被掉函數需要告訴調用者自己的指標地址,但在JAVA中沒有指標,怎麼辦。我們可以通過介面(interface)來實現定義回呼函數。
定義一個通知介面:
public interface Notice { public void noticeMe(String msg);}
改寫專案經理類:
public class ProjectManager implements Notice{private String name;public ProjectManager(String name){ this.name =name;}public String getName(){return this.name;}/** * 通知方法 * @param msg */@Overridepublic void noticeMe(String msg){System.err.println(msg);}/** * 安排任務 * @param task */public void arrange(String task){//安排程式員幹活new Programmer().receiveTask(task, this);}public void doOtherWork(){System.err.println("專案經理幹其他事情...");}}
改寫程式員類
import java.util.concurrent.TimeUnit;public class Programmer{ //指定了通知方式 Notice notice; /**程式員接受任務*/ public void receiveTask(String task,Notice notice) { this.notice = notice; try { //程式員開始執行任務 this.excuteTask(task); } catch (InterruptedException e) { e.printStackTrace(); } } /**執行任務*/ private void excuteTask(String task) throws InterruptedException { System.err.println("執行專案經理:安排的任務-->"+task); //任務執行中 TimeUnit.SECONDS.sleep(1); //任務完成 this.finished(task); } /**任務完成*/ public void finished(String task) { //擷取通知專案經理的方法,並發出通知 //進行回調通知 notice.noticeMe("你好,你安排的任務"+task+"已經完成。"); }}
那我們為什麼要使用回呼函數呢。
簡單來說就是,我自己活太多,或者有其他的事需要做,自己不想做,就把這個活分配給別人去完成,並把完成的結果告訴我就行了。
如果看到這裡你若還沒有懂的話,那我換一種方式表達:回呼函數就是別人要調用我的時候,我要告訴別人我這個方法的地址在那裡,然後別人直接找這個地址就行,不用再去向系統申請記憶體位址然後去找這個方法在哪裡。