java的回调函数,写个简单的实例说明java回调机制
如何解决写爬虫IP受阻的问题?立即使用。
模块间调用
在一个应用系统中,无论用什么语言开发,模块之间都要有调用。有几种打电话的方式:
(1)同步呼叫
同步是最基本最简单的调用方式。A类的方法A()调用B类的方法B(),一直等到方法B()执行完毕,方法A()继续往下走。这种调用方式适用于方法b()执行时间不长的情况,因为如果B()方法执行时间长或者直接被阻塞,A()方法的剩余代码就无法执行,会阻塞整个进程。
(2)异步调用
异步调用是一种解决同步调用可能被阻塞,导致整个进程被卡住的调用方法。类A的方法方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行,这样无论方法B()的执行时间有多长,都不会阻塞方法A()的执行。
但这样一来,由于方法A()并不等待方法B()的执行,所以当方法A()需要方法B()的执行结果时(视具体业务而定,有些业务如启动异步线程发送微信通知、刷新缓存等并不是必须的),必须通过一定的方式监控方法B()的执行结果。
(3)回调
最后是回调,回调的思路是:
类A的a()方法调用类B的b()方法类B的b()方法执行完毕主动调用类A的callback()方法是双向的一种调用方式,构成了上图。
代码示例
接下来,我们来看看回调的代码示例。代码模拟了这样一个场景:老师向学生提问,学生思考后回答老师。
首先,定义一个回调接口。方法只有一个,tellAnswer(int answer),就是学生思考后告诉老师答案:
/**
*回拨接口,源自http://www.cnblogs.com/xrq730/p/6424471.html
*/
公共接口回调{
public void tell answer(int answer);
}定义一个教师对象并实现回调接口:
/**
*老师,原籍http://www.cnblogs.com/xrq730/p/6424471.html.
*/
公共课老师实现回调{
私生学生;
公立教师(学生){
this.student=学生;
}
public void askQuestion() {
student.resolveQuestion(这);
}
@覆盖
public void tell answer(int answer){
System.out.println(知道了,你的答案是答案);
}
}教师对象有两个公共方法:
(1)回调接口tellAnswer(int answer),即学生回答完问题后老师要做的事情。
(2) askQuestion(),提问的方法,就是向学生提问。
然后定义一个学生界面。当然,学生解决问题,但会收到一个回调参数,以便学生知道解决问题后向谁报告:
/**
*学生界面,来自http://www.cnblogs.com/xrq730/p/6424471.html
*/
公共界面学生{
public void resolveQuestion(回调回调);
}最后,定义一个名为Ricky的特定学生:
/**
*一个叫瑞奇的同学解决了老师提出的问题。原文来自http://www.cnblogs.com/xrq730/p/6424471.html.
*/
公共类Ricky实现Student {
@覆盖
public void resolveQuestion(回调回调){
//模拟解决问题
尝试{
thread . sleep(3000);
} catch (InterruptedException e) {
}
//打回去告诉老师作业写了多久。
callback . tell answer(3);
}
}解题后,16行向老师汇报答案。
编写一个相对简单的测试类:
/**
*回拨测试,源自http://www.cnblogs.com/xrq730/p/6424471.html
*/
公共类回调测试{
@测试
public void testCallback() {
学生学生=新瑞奇();
老师老师=新老师(学生);
老师. ask question();
}
}代码运行结果只有一行:
我明白了。你的答案是3。简单总结分析一下这个例子:
(1)教师调用学生接口方法resolveQuestion向学生提问。
(2)学生解题后调用老师的回调方法tellAnswer。
这样的一套流程构成了双向调用关系。
代码分析
分析上面的代码,我在这里做了两层抽象:
(1)抽象老师。
抽象了老师之后,对于学生来说,就没必要在意是哪个老师问我的问题了。只要我根据问的问题得到答案,然后告诉提问的老师,即使老师换了一茬又一茬,对我的学生也没有影响。(2)抽象学生。
抽象出学生后,对于老师来说就非常灵活了,因为老师可能不会向一个学生提问,而可能会同时向Ricky、Jack和Lucy提问,这样就可以将成员变量student改为ListStudent,从而在提问时遍历学生列表进行提问。然后从每个学生那里得到答案。这个例子是界面作用的典型例子。我想,有些朋友可能不理解接口的好处。不了解接口好处的可以重点看这个例子,了解更多。
总结一下,回调的核心就是回调方将本身即this传递给调用方,这样打电话的人打完电话后就可以告诉打电话的人想知道什么。回调是一种理念,也是一种机制。至于如何实现,如何通过代码让回调变得优雅和可伸缩,就看开发者的个人水平和开发者对业务的理解了。
同步回调与异步回调
举上面的例子,有人可能会问这个问题:
这个问题没有错。我们可以从两个角度来理解。
首先,老师不只是想要学生的答案怎么办?
可能这个老师是一个比较喜欢听学生解题思路的老师吧。在得到学生的答案之前,老师想先知道学生的名字和他们的解题思路。当然有人会说,那我可以定义一个对象,把学生的名字和解题思路加进去。在我看来,这种说法有两个问题:
(1)如果老师想要的数据越来越多,那么返回的对象就会越来越大,而回调可以用来分离数据,把一批数据放到回调方法中进行处理。至于哪些数据取决于具体业务,如果需要添加返回参数,可以直接在回调方法中添加。
(2)不能解决老师想在学生回答之前得到学生名字和学生解题思路的问题。
所以我觉得没必要简单的返回某个结果,可以直接用同步调用。但是,如果要处理的数据种类很多,并且数据分为主次,那么使用回调是更合适的选择,首先处理的数据应该在回调方法中处理掉。
另一个理解的角度更重要,就是题目中提到的同步回调和异步回调。Example是一个同步回调的例子,意思是老师问瑞奇一个问题,瑞奇给出答案,老师问下一个同学,得到答案后继续问下一个同学。这是一个正常的场景,但是如果我换一个场景:
这种情景就相当于说学生思考完了要有办法告诉老师。有两种解决方案:
(1)使用未来可调用方法,等待异步线程执行结果,相当于同步调用的一个变种,因为它的本质是方法返回一个结果,也就是学生的答案。
(2)使用异步回调,学生回答完问题后,调用回调接口方法告诉老师答案。由于教师对象被抽象到回调接口中,因此该方法具有很好的可伸缩性。如前所述,即使老师换了一茬又一茬,对于学生来说,他们关心的只是调用回调接口返回必要的信息。
更多信息请关注java基础课程专栏。以上是Java回调机制的详细介绍。更多信息请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。