对于Java回调的最深刻解析
原文鏈接:http://www.jianshu.com/p/f177a6a41a43
第一站,來個騷問題
開始之前,先想象一個場景:幼稚園的小朋友(邱同學)剛剛學習了10以內的加法。
老師大人在黑板上寫一個式子 “1 + 1 = ”,由邱同學來填空。由于已經學習了10以內的加法,邱同學可以完全靠自己來計算這個題目,額,這個需求簡單吧,就寫一個add(int a,int b) 不就解決了么,是的。那動手吧:
public class Student {private String name = null;public Student(String name){ this.name = name;}public void setName(String name){ this.name = name;}private int add(int a, int b){ return a + b;}public void fillBlank(int a, int b){int result = add(a, b);System.out.println(name + "心算:" + a + " + " + b + " = " + result);} }邱同學在填空(fillBalnk)的時候,直接心算(add)了一下,得出結果是2,并將結果寫在空格里,測試:
public class Test {public static void main(String[] args){int a = 1;int b = 1;Student s = new Student("邱同學");s.fillBlank(a, b);} }運行結果如下:
邱同學心算:1 + 1 = 2該過程完全由Student類的實例對象單獨完成,并未涉及回調機制。
第二站,進擊的老師
課間,老師突發奇想在黑板上寫了“168 + 291 = ”讓邱同學完成,然后回辦公室了。
呀兒咯!為什么所有老師都跟邱同學過不去啊?明明超綱了好不好~~
這時候邱同學然而明顯不能再像上面那樣靠心算來完成了,正在一臉懵逼的時候,同桌的小嫻嫻同學遞過來一個只能計算加法的計算器,而邱同學恰好知道怎么用計算器,于是通過計算器計算得到結果并完成了填空。
計算器的代碼為:
public class Calculator {public int add(int a, int b){ return a + b;} }修改Student類,添加使用計算器的方法:
public class Student {private String name = null;public Student(String name){ this.name = name;}public void setName(String name){ this.name = name;}@SuppressWarnings("unused")private int calcADD(int a, int b){ return a + b;}private int useCalculator(int a, int b){ return new Calculator().add(a, b);}public void fillBlank(int a, int b){int result = useCalculator(a, b);System.out.println(name + "使用計算器:" + a + " + " + b + " = " + result);} }測試代碼如下:
public class Test {public static void main(String[] args){int a = 168;int b = 291;Student s = new Student("邱同學");s.fillBlank(a, b);} }運行結果如下:
邱同學使用計算器:168 + 291 = 459該過程中仍未涉及到回調機制,但是部分邱同學的部分工作已經實現了轉移,由計算器來協助實現。
第三站,暴走的老師
發現邱同學完成了3位數的加法,老師覺得邱同學很聰明,是個可塑之才。于是又在黑板上寫下了“26549 + 16487 = ”,讓邱同學上課之前完成填空,然后又回辦公室了。
邱同學看著教室外面撒歡兒的小伙伴,不禁悲從中來。再不出去玩,這個課間就要廢了啊!!!! 看著小嫻嫻再一次遞上來的計算器,邱同學心生一計:讓小嫻嫻代勞。
邱同學告訴小嫻嫻題目是“26549 + 16487 = ”,然后指出填寫結果的具體位置,然后就出去快樂的玩耍了。
這里,不把小嫻嫻單獨實現出來,而是把這個只能算加法的計算器和小嫻嫻看成一個整體,一個會算結果還會填空的超級計算器。這個超級計算器需要傳的參數是兩個加數和要填空的位置,而這些內容需要邱同學提前告知,也就是邱同學要把自己的一部分方法暴漏給小嫻嫻,最簡單的方法就是把自己的引用和兩個加數一塊告訴小嫻嫻。
因此,超級計算器的add方法應該包含兩個操作數和邱同學自身的引用,代碼如下:
public class SuperCalculator {public void add(int a, int b, Student xiaoming){int result = a + b;xiaoming.fillBlank(a, b, result);} }邱同學這邊現在已經不需要心算,也不需要使用計算器了,因此只需要有一個方法可以向小嫻嫻尋求幫助就行了,代碼如下:
public class Student {private String name = null;public Student(String name){ this.name = name;}public void setName(String name){ this.name = name;}public void callHelp (int a, int b){ new SuperCalculator().add(a, b, this);}public void fillBlank(int a, int b, int result){System.out.println(name + "求助小嫻嫻計算:" + a + " + " + b + " = " + result);} }測試代碼如下:
public class Test {public static void main(String[] args){int a = 26549;int b = 16487;Student s = new Student("邱同學");s.callHelp(a, b);} }運行結果為:
邱同學求助小嫻嫻計算:26549 + 16487 = 43036執行流程為:邱同學通過自身的callHelp方法調用了小嫻嫻(new SuperCalculator())的add方法,在調用的時候將自身的引用(this)當做參數一并傳入,小嫻嫻在使用計算器得出結果之后,回調了邱同學的fillBlank方法,將結果填在了黑板上的空格里。
燈燈燈!到這里,回調功能就正式登場了,邱同學的fillBlank方法就是我們常說的回調函數。
通過這種方式,可以很明顯的看出,對于完成老師的填空題這個任務上,邱同學已經不需要等待到加法做完且結果填寫在黑板上才能去跟小伙伴們撒歡了,填空這個工作由超級計算器小嫻嫻來做了。回調的優勢已經開始體現了。
第四站,不明真相的吃瓜婆婆
幼稚園的門口有一個頭發花白的老婆婆,每天風雨無阻在那里擺著地攤賣一些快過期的垃圾食品。由于年紀大了,腦子有些糊涂,經常算不清楚自己掙了多少錢。有一天,她無意間聽到了邱同學跟小伙伴們吹噓自己如何在小嫻嫻的幫助下與幼師斗智斗勇。于是,婆婆決定找到小嫻嫻牌超級計算器來做自己的小幫手,并提供一包衛龍辣條作為報酬。小嫻嫻經不住誘惑,答應了。
之前,我們發現小嫻嫻牌超級計算器的add方法需要的參數是兩個整型變量和一個Student對象,但是老婆婆她不是學生,是個小商販啊,這是最尷尬的,所以這里肯定要做修改。這種情況下,我們很自然的會想到繼承和多態。如果讓邱同學這個學生和老婆婆這個小商販從一個父類進行繼承,那么我們只需要給小嫻嫻牌超級計算器傳入一個父類的引用就可以啦。
不過,實際使用中,考慮到java的單繼承,以及不希望把自身太多東西暴漏給別人,這里使用從接口繼承的方式配合內部類來做。
換句話說,小嫻嫻希望以后繼續向班里的小朋友們提供計算服務,同時還能向老婆婆提供算賬服務,甚至以后能夠拓展其他人的業務,于是她向所有的顧客約定了一個辦法,用于統一的處理,也就是自己需要的操作數和做完計算之后應該怎么做。這個統一的方法,小嫻嫻做成了一個接口,提供給了大家,代碼如下:
public interface doJob { public void fillBlank(int a, int b, int result); }同時,小嫻嫻修改了自己的計算器,使其可以同時處理不同的實現了doJob接口的人,代碼如下:
public class SuperCalculator {public void add(int a, int b, doJob customer){int result = a + b;customer.fillBlank(a, b, result);} }邱同學和老婆婆拿到這個接口之后,只要實現了這個接口,就相當于按照統一的模式告訴小嫻嫻得到結果之后的處理辦法,按照之前說的使用內部類來做,代碼如下:
邱同學的:
public class Student {private String name = null;public Student(String name){ this.name = name;}public void setName(String name){ this.name = name;}public class doHomeWork implements doJob{@Overridepublic void fillBlank(int a, int b, int result){ System.out.println(name + "求助小嫻嫻計算作業:" + a + " + " + b + " = " + result);}}public void callHelp (int a, int b){ new SuperCalculator().add(a, b, new doHomeWork());} }老婆婆的:
public class Popo {private String name = null;public Seller(String name){ this.name = name;}public void setName(String name){ this.name = name;}public class doHomeWork implements doJob{@Overridepublic void fillBlank(int a, int b, int result){ System.out.println(name + "求助小嫻嫻幫忙算數:" + a + " + " + b + " = " + result + "元");}}public void callHelp (int a, int b){ new SuperCalculator().add(a, b, new doHomeWork());} }測試程序如下:
public class Test {public static void main(String[] args){int a = 60;int b = 50;int c = 40;int d = 30;Student s = new Student("邱同學");s.callHelp(a, b);Popo p= new Popo("不明真相的婆婆");p.callHelp(c, d);} }運行結果為:
邱同學求助小嫻嫻計算作業:a+b=110;不明真相的婆婆求助小嫻嫻幫忙算數:c+d=70;總結
以上是生活随笔為你收集整理的对于Java回调的最深刻解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何配置Filter过滤器处理JSP中文
- 下一篇: Oracle报错:类型长度大于最大值解决