callback不动产登记是什么意思思及用法

回调函数(callback)是什么?
网上搜到的资源讲起来好凌乱
按投票排序
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。回答完毕。
这个是程序上的概念。本质上是叫别人做事,传进去的额外信息。比如,A叫B做事,根据粒度不同,可以理解成A函数调用B函数,或者A类使用B类,或者A组件使用B组件等等。反正就是A叫B做事。当B做这件事情的时候,自身的需要的信息不够,而A又有。就需要A从外面传进来,或者B做着做着主动向外面申请。对于B来说,一种被动得到信息,一种是主动去得到信息,有人给这两种方式术语,叫信息的push,和信息的pull。接着,A调用B,A向B传参数。int max(int a, int b); 要使用这函数max, 得到两者最大的值, 外面就要传进来a, b。这个好理解。再跟着,就来到计算机中比较诡异的地方。也就是代码(code)和数据(data)的统一,这是一个槛,如果不打通这个,很多概念就不清楚。我们常常说计算机程序分成code和data两部分。很多人就会觉得,code是会运行的,是动的,data是给code使用,是静态的,这是两种完全不同的东西。其实code只是对行为的一种描述,比如有个机器人可以开灯,关灯,扫地。跟着我要机器人开灯,扫地,关灯。如果跟机器人约定好,0表示开灯,1表示关灯,2表示扫地。我发出指令,0 1 2 1 0。跟着就可以控制机器人开灯,扫地,关灯。再约定用二进制表示,两位一个指令,就有一个数字串,,这个时候这串数字就描述了机器人的一系列动作,这个就是从一方面理解是code,可以它可以控制机器人的行为。但另一方面,它可以传递,可以记录,可以修改,也就是数据。只要大家都协商好,code就可以编码成data, 将data解释运行的时候,也变成了code。这个地方扯开了。我自己是不区分code和data的,统一称为信息。那既然int max(int a, int b)中int,double等表示普通data的东西可以传递进去,凭什么表示code的函数就不可以传进去了。有些语言确实是不区分的,它的function(表示code)跟int, double的地位是一样的。这种语言就为函数是第一类值。但问题是,有些语言是不能存储函数,不能动态创建函数,不能动态销毁函数。(这里函数是已经是广义的了,用来表示代码code)。只能存储一个指向函数的指针,这种语言称为函数是第二类值。另外有些语言不单可以传递函数,函数里面又用到一些外部信息(包括code, data)。那些语言可以将函数跟函数所用到的信息一起传递存储。这种将函数和它所用的信息作为一个整体,就为闭包。再次声明,将代码和数据打通,统一起来,是一个槛。过了这个槛,很多难以理解的概念就会清晰很多。比如一些修改自身的程序啊,数据驱动啊,先设计数据再写程序等等。来到这里,其实已经没有什么好说的了。回调函数也就是是A让B做事,B做着做着,信息不够,不知道怎么做了,就再让外面处理。比如排序,A让B排序,B会做排序,但排序需要知道哪个比哪个大,这点B自己不知道,就需要A告诉它。而这种判断那个大,本身是一种动作,既然C语言中不可以传进第一值的函数,就设计成传递第二值的函数指针,这个函数指针就是A传向B的信息,用来表示一个行为。这里本来A调用B的,结果B又调用了A告诉它的信息,也就叫callback。再比如A让B监听系统的某个消息,比如敲了哪个键。跟着B监听到了,但它不知道怎么去处理这个消息,就给外面关心这个消息,又知道怎么去处理这个消息的人去处理,这个处理过程本事是个行为,既然这个语言不可以传递函数,又只能传一个函数指针了。跟着有些人有会引申成,什么注册啊,通知啊等等等。假如B做监听,C, D, E, F, G, H告诉B自己有兴趣知道这消息,那B监听到了就去告诉C,D,E,F,G等人了,这样通知多人了,就叫广播。其实你理解了,根本不用去关心术语的。术语是别人要告诉你啊,或者你去告诉人啊,使用的一套约定的词语。本质上就个东西,结果会有很多术语的。跟着再将回调的概念进化,比如某人同时关心A,B,C,D,E,F事件,并且这些事件是一组的,比如敲键盘,鼠标移动,鼠标点击等一组。将一组事件结合起来。在有些语言就变成一个接口,接口有N个函数。有些语言就映射成一个结构,里面放着N个函数指针。跟着就不是将单个函数指针传进去,而是将接口,或者函数指针的结构传进去。这些根据不同的用途,有些人叫它为代理啊,监听者啊,观察者啊等等。
什么是回调函数?我们绕点远路来回答这个问题。编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写库;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数(to register a callback function)。如下图所示(图片来源:维基百科):可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。回调机制的优势从上面的例子可以看出,回调机制提供了非常大的灵活性。请注意,从现在开始,我们把图中的库函数改称为中间函数了,这是因为回调并不仅仅用在应用和库之间。任何时候,只要想获得类似于上面情况的灵活性,都可以利用回调。这种灵活性是怎么实现的呢?乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现两者之间的一个关键的不同:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。请看下面这段Python写成的回调的简单示例:`even.py`#回调函数1
#生成一个2k形式的偶数
def double(x):
return x * 2
#回调函数2
#生成一个4k形式的偶数
def quadruple(x):
return x * 4
`callback_demo.py`from even import *
#接受一个生成偶数的函数作为参数
#返回一个奇数
def getOddNumber(k, getEvenNumber):
return 1 + getEvenNumber(k)
#起始函数,这里是程序的主函数
def main():
#当需要生成一个2k+1形式的奇数时
i = getOddNumber(k, double)
#当需要一个4k+1形式的奇数时
i = getOddNumber(k, quadruple)
#当需要一个8k+1形式的奇数时
i = getOddNumber(k, lambda x: x * 8)
if __name__ == "__main__":
运行`callback_demp.py`,输出如下:3
上面的代码里,给`getOddNumber`传入不同的回调函数,它的表现也不同,这就是回调机制的优势所在。值得一提的是,上面的第三个回调函数是一个匿名函数。易被忽略的第三方通过上面的论述可知,中间函数和回调函数是回调的两个必要部分,不过人们往往忽略了回调里的第三位要角,就是中间函数的调用者。绝大多数情况下,这个调用者可以和程序的主函数等同起来,但为了表示区别,我这里把它称为起始函数(如上面的代码中注释所示)。之所以特意强调这个第三方,是因为我在网上读相关文章时得到一种印象,很多人把它简单地理解为两个个体之间的来回调用。譬如,很多中文网页在解释“回调”(callback)时,都会提到这么一句话:“If you call me, I will call you back.”我没有查到这句英文的出处。我个人揣测,很多人把起始函数和回调函数看作为一体,大概有两个原因:第一,可能是“回调”这一名字的误导;第二,给中间函数传入什么样的回调函数,是在起始函数里决定的。实际上,回调并不是“你我”两方的互动,而是ABC的三方联动。有了这个清楚的概念,在自己的代码里实现回调时才不容易混淆出错。另外,回调实际上有两种:阻塞式回调和延迟式回调。两者的区别在于:阻塞式回调里,回调函数的调用一定发生在起始函数返回之前;而延迟式回调里,回调函数的调用有可能是在起始函数返回之后。这里不打算对这两个概率做更深入的讨论,之所以把它们提出来,也是为了说明强调起始函数的重要性。网上的很多文章,提到这两个概念时,只是笼统地说阻塞式回调发生在主调函数返回之前,却没有明确这个主调函数到底是起始函数还是中间函数,不免让人糊涂,所以这里特意说明一下。另外还请注意,本文中所举的示例均为阻塞式回调。延迟式回调通常牵扯到多线程,我自己还没有完全搞明白,所以这里就不多说了。
一般写程序是你调用系统的API,如果把关系反过来,你写一个函数,让系统调用你的函数,那就是回调了,那个被系统调用的函数就是回调函数。
回调函数:函数可以理解为一个功能体,执行它可以完成一个任务。回调函数本质上就是一个函数,只是执行时间和执行主体与普通的函数稍有区别。-----举个例子的分割线------------你去食堂打饭,你喜欢吃小炒热饭菜,所以你去了一个小炒窗口。你跟老板说了要×××盖饭,老板说:你是100号,喊到你的号你就来拿菜。然后你在旁边跟同学吹牛、或者看手机、或者干点你想干的任何事情。。。然后你听到老板喊100号并且把菜放到窗口,你走到窗口,拿到你的菜。这里面就有典型的异步操作、回调函数的概念。-----下面很烦的分割线------------好吧,先搞清楚一些问题再回头分析回调函数在什么场景有用?我要在特定时候执行一个任务,至于是什么时候我自己都不知道。比如某一时间到了或者某一事件发生或者某一中断触发。回调函数怎么起作用?把我要执行的这个任务写成一个函数,将这个函数和某一时间或者事件或者中断建立关联。当这个关联完成的时候,这个函数华丽的从普通函数变身成为回调函数。回调函数什么时候执行?当该回调函数关心的那个时间或者事件或者中断触发的时候,回调函数将被执行。一般是触发这个时间、事件或中断的程序主体(通常是个函数或者对象)观察到有一个关注这个东东的回调函数的时候,这个主体负责调用这个回调函数。回调函数有什么好处?最大的好处是你的程序变成异步了。也就是你不必再调用这个函数的时候一直等待这个时间的到达、事件的发生或中断的发生(万一一直不发生,你的程序会怎么样?)。再此期间你可以做做别的事情,或者四处逛逛。当回调函数被执行时,你的程序重新得到执行的机会,此时你可以继续做必要的事情了。回调函数有什么问题吗?既然有人问,当然就会有点问题。一个是学习成本会比普通函数高,需要有一定的抽象思维能力,需要对应用场景的理解。另一个是回调函数很多情况下会附带有跨线程操作甚至于跨进程的操作,这些都是异步带来的成本。-----回调分析的分割线------------你去食堂打饭,你喜欢吃小炒热饭菜,所以你去了一个小炒窗口。你跟老板说了要×××盖饭,老板说:你是100号,喊到你的号你就来拿菜。然后你在旁边跟同学吹牛、或者看手机、或者干点你想干的任何事情。。。然后你听到老板喊100号并且把菜放到窗口,你走到窗口,拿到你的菜。这里面有几个函数:老板的部分:1、老板提供一个点餐的函数 boss.Order(string 菜名,double 钱)2、老板有个做饭的函数,此函数耗时较长boss.Cook()3、老板提供一个事件,当boss.cook()执行完时,该事件被触发,boss.OnCookF你的部分:1、你需要有一个函数去订餐,也就是你的函数中需要执行类似于boss.Order("红烧肉盖浇饭",20),比如是me.Hungry()2、你需要有一个函数作为回调函数去关注boss.OnCookFinish事件,这样当老板做好饭,你就可以知道是不是你的好了。由于老板的事件发生的时候中会喊编号并且吧菜放到窗口,所以你的回调函数需要能够接受1个编号和1个菜作为参数。比如me.AcceptFood(int currNumber,object food)所以整个程序的流程其实是这样的。me.Hungry(){ boss.Order("红烧肉盖浇饭",20); boss.OnCookFinish+=me.AcceptF//此处表面,AcceptFood这个回调函数关心OnCookFinish事件,并且变成这个事件的回调函数 //此时这个函数执行完,不再等待}boss.Order("红烧肉盖浇饭",20){ //收钱 //配菜
前2个耗时较短 boss.Cook();//此处一般会开新线程执行cook动作}boss.Cook(){ //cooking~~~~~~~~~~ //完成了,下面将要触发事件,系统将检查这个事件是否有回调函数关心,有的话逐个回调。 OnCookFinish(100号,红烧肉盖浇饭);}至此案例基本完成了一个完整的任务流程。======最终总结的分割线==========回调函数在异步处理过程中的一个必要手段。目的是让me不需要等boss的长时间操作,可以在这段时间做点别的事情。------关于硬件中断------------硬件中断也会有对应的函数做处理,所以这个函数从概念上来说也就是个回调函数。无非前文讨论的是软件层面的,硬件中断对应的函数是OS层面甚至于硬件层面的。没什么本质的区别。
回调方法介绍之中国好室友篇(Java示例)前言在Java社区的各种开源工具中,回调方法的使用俯拾即是。所以熟悉回调方法无疑能加速自己对开源轮子的掌握。网上搜了一些文章,奈何对回调方法的介绍大多只停留在什么是回调方法的程度上。本篇文章尝试从回调方法怎么来的、为什么要使用回调方法以及在实际项目中如何使用等方面来介绍下。场景场景选择的得当与否,很影响读者的继续阅读的兴趣甚至理解的主动性(长期作为互联网技术博文读者的我,深有感触)。好场景私以为是:熟悉且简单。本例小心翼翼选择的场景是:写作业。(hope you like)自己写注:写作业这个动作至少交代三个方面:谁,什么动作(写),写什么。下面先从(有个学生,写,作业)开始。# 1. 有个学生
Student student = new Student();
# 2. 该学生有写作业这个动作需要执行
student.doHomeWork(someHomeWork);
# 3. 注意到这个写作业这个动作是需要得到入参“作业”的后才能进行的。所以给这个学生new了个简单的题目做。
String aHomeWork = "1+1=?";
student.doHomeWork(aHomeWork);
至此,完成写作业的动作。完整代码public class Student {
public void doHomeWork(String homeWork) {
System.out.println("作业本");
if("1+1=?".equals(homeWork)) {
System.out.println("作业:"+homeWork+" 答案:"+"2");
System.out.println("作业:"+homeWork+" 答案:"+"不知道~~");
public static void main(String[] args) {
Student student = new Student();
String aHomeWork = "1+1=?";
student.doHomeWork(aHomeWork);
程序执行作业本
作业:1+1=? 答案:2
我们一定要把焦点聚焦到,”写作业“这个需求上面。该学生写作业的方法是现成的,但是需要有作业作为入参,怎么获取作业才是完成动作的关键。希望这点能深深印入我们的脑海。让室友帮忙解答上面的例子中该同学自己调用自己的方法,把收到的homework直接写了。但是现实可能会出现各种各样的问题导致该同学不能(xiang)自己来做。比如他想玩游戏或者有约会。所以他拜托了他的好室友(roommate)来帮忙写下。该怎么实现呢。#1. 因为室友帮忙写,所以在doHomeWork动作里面,就不需要有逻辑判断的代码,因为舍友会直接把答案写进来。改成:
student.doHomeWork(aHomeWork, theAnswer);
#上句中做作业的动作支持传入“作业”和“答案”,有了这两个,就说明能做好作业了。
#其中aHomeWork作业是已知的,但是theAnswer这个答案却是室友提供的。
#室友怎么才能提供答案呢,最简单是,室友这个对象直接提供一个传入作业,传出答案的方法,这样该同学就可以直接调用了。
RoomMate roomMate = new RoomMate();
String theAnswer = roomMate.getAnswer(aHomeWork);
student.doHomeWork(aHomeWork, theAnswer);
完整代码public class Student {
public void doHomeWork(String homeWork, String answer) {
System.out.println("作业本");
if(answer != null) {
System.out.println("作业:"+homeWork+" 答案:"+ answer);
System.out.println("作业:"+homeWork+" 答案:"+ "(空白)");
public static void main(String[] args) {
Student student = new Student();
String aHomeWork = "1+1=?";
RoomMate roomMate = new RoomMate();
String theAnswer = roomMate.getAnswer(aHomeWork);
student.doHomeWork(aHomeWork, theAnswer);
public class RoomMate {
public String getAnswer(String homework) {
if("1+1=?".equals(homework)) {
return "2";
return null;
程序执行作业本
作业:1+1=? 答案:2
怒,说好的回调方法呢~~因为到目前为止,不需要使用回调方法。技术总是伴随新的需求出现的。好,给你新的需求。注意重点来了我们回顾下这两行代码#室友写好作业
String theAnswer = roomMate.getAnswer(aHomeWork);
#该同学直接抄答案,完成作业
student.doHomeWork(aHomeWork, theAnswer);
该同学想了想,你给了答案有屁用,还得要我自己誊写到作业本上面去(执行自己的做作业方法)。你就不能直接调用我的做作业方法帮我把答案写好,把作业做完得了。让室友直接把作业写了经不住该同学的软磨硬泡,“中国好室友”答应了。怎么实现呢。再回顾下做作业的全过程#待解决的作业
String aHomeWork = "1+1=?";
#室友写出答案
String theAnswer = roomMate.getAnswer(aHomeWork);
#该同学调用,自己把答案写到作业本。(也即是这个步骤不给调用了)
student.doHomeWork(aHomeWork, theAnswer);
#做作业必须得调用这个方法,而根据需求这个方法必须由室友去调用。那很显然,该室友得保持一个该同学的引用,才能正常调用啊。
#室友说,那你在调用getAnswer方法的时候,除了传入作业,还需要把自己的引用放里面。这样我做完了,直接调用你的做作业方法就行了。
roomMate.getAnswer(aHomeWork,student);
完整代码public class Student {
public void doHomeWork(String homeWork, String answer) {
System.out.println("作业本");
if(answer != null) {
System.out.println("作业:"+homeWork+" 答案:"+ answer);
System.out.println("作业:"+homeWork+" 答案:"+ "(空白)");
public static void main(String[] args) {
Student student = new Student();
String aHomeWork = "1+1=?";
RoomMate roomMate = new RoomMate();
roomMate.getAnswer(aHomeWork,student);
public class RoomMate {
public void getAnswer(String homework, Student student) {
if("1+1=?".equals(homework)) {
student.doHomeWork(homework, "2");
student.doHomeWork(homework, "(空白)");
执行程序作业本
作业:1+1=? 答案:2
回调方法在上述“让室友直接把作业写了”的例子中,其实已经体现了回调的意思。场景的核心在于这位学生要把作业给做了。简单点描述:这位学生告诉室友要做什么作业,并把自己的引用也给了室友。该室友得到作业,做完后直接引用该学生并调用其做作业的方法,完成代写作业的任务。稍微复杂点描述:该学生做作业的方法有两个入参,一个是作业题目(已知),一个是作业答案(未知)。室友为了帮助他写作业提供了一个方法,该方法有两个入参,一个是作业题目,一个是该学生的引用(解出答案得知道往哪写)。程序执行时,该学生只要调用室友的代写作业方法就行了。一旦室友得到答案,因为有该学生的引用,所以直接找到对应方法,帮助其完成作业。再复杂点描述:学生调用室友的替写作业方法,注册了题目和自己的引用。室友的替写作业方法被调用,则会根据题目完成作业后,再回调该同学写作业方法,完成作业。再抽象点描述:类A调用类B的方法b(传入相关信息),类B的方法在执行完后,会将结果写到(再回调)类A的方法a,完成动作。(其实方法a就是传说中的回调方法啦)最抽象的描述:调用,回调。接口方式的回调方法常常使用回调方法的同学可能会说,我从来也没见过直接把对象的引用写到第一次调用方法里面的。嗯,是的,下面就来填上述例子留下的“天坑”(实际项目中常见到)。问题:在调用方法中直接传对象引用进去有什么不好?只说一点,只是让别人代写个方法,犯得着把自己全部暴露给别人吗。万一这个别人是竞争对手的接口咋办。这就是传说中的后面代码吗(/tx)。总之这样做是非常不安全的。因此,最常规的《调用,回调》实现,是(你已经猜到了)使用接口作为引用(说的不严谨)传入调用的方法里面。我承认,怎么将思路跳转到使用接口的花了我好长时间。我们再看RoomMate类的getAnswer方法。public class RoomMate {
public void getAnswer(String homework, Student student) {
if("1+1=?".equals(homework)) {
student.doHomeWork(homework, "2");
student.doHomeWork(homework, "(空白)");
关键在于,该方法的用途是来解决某学生提出的某个问题。答案是通过学生的doHomeWork方法回调传回去的。那假设有个工人也有问题,这位室友该怎么解决呢。再开个方法,专门接收工人的引用作为传参?当然不用,只要你这个引用包含了doHomeWork()方法,那么不论你是工人、警察还是环卫工人,直接调用getAnswer()方法就能解决你提的问题。至此我们的思路达到了:所有的对象要有同一个方法,所以自热而然就引出了接口概念。只要这些对象都实现了某个接口就行了,这个接口的作用,仅仅是用来规定那个做作业的方法长什么样。这样工人实现了该接口,那么就有了默认继承的做作业方法。工人再把自己的引用抛给该室友的时候,这个室友就不需要改动任何代码,直接接触答案,完成任务了。创建一个做作业的接口,专门规定,需要哪些东西(问题和答案)就能做作业.public interface DoHomeWork {
void doHomeWork(String question, String answer);
改动下中国好室友的解答方法。任意一个实现了DoHomeWork 接口的someone,都拥有doHomeWork(String question,String answer)的方法。这个方法就是上面已经提到的“回调方法”。someone先调用下好室友的getAnswer()方法,把问题和自己传进来(此为调用),好室友把问题解答出之后,调用默认提供的方法,写完作业。思考下,因为是以接口作为参数类型的约定,在普通对象upcast向上转型之后将只暴露接口描述的那个方法,别人获取到这个引用,也只能使用这个(回调)方法。至此,遗留的重大安全隐患重要解决。完整代码public class RoomMate {
public void getAnswer(String homework, DoHomeWork someone) {
if("1+1=?".equals(homework)) {
someone.doHomeWork(homework, "2");
someone.doHomeWork(homework, "(空白)");
package org.futeng.designpattern.callback.test1;
public class Worker implements DoHomeWork {
public void doHomeWork(String question, String answer) {
System.out.println("作业本");
if(answer != null) {
System.out.println("作业:"+question+" 答案:"+ answer);
System.out.println("作业:"+question+" 答案:"+ "(空白)");
public static void main(String[] args) {
Worker worker = new Worker();
String question = "1+1=?";
new RoomMate().getAnswer(question, worker);
执行程序作业本
作业:1+1=? 答案:2
至此,调用+回调的文章是不是写完了呢。咳咳,还木有。大家喝点茶再忍耐下。(我都写一天了 - -)常规使用之匿名内部类作为平凡的屁民,实用主义是我们坚持的生存法则。所以凡事用不到的技术都可以不学,凡事学了却不用的技术等于白学。我们之前已经定性,中国好室友RoomMate类拥有接受任何人任何问题挑战的潜质。自从好室友出名之后,有个不知道什么工作(类型)的人也来问问题。反正只要实现了回调接口,好室友都能调用你默认继承的回调方法,那就放马过来吧。package org.futeng.designpattern.callback.test1;
public class RoomMate {
public void getAnswer(String homework, DoHomeWork someone) {
if("1+1=?".equals(homework)) {
someone.doHomeWork(homework, "2");
someone.doHomeWork(homework, "(空白)");
public static void main(String[] args) {
RoomMate roomMate = new RoomMate();
roomMate.getAnswer("1+1=?", new DoHomeWork() {
public void doHomeWork(String question, String answer) {
System.out.println("问题:"+question+" 答案:"+answer);
看到稍显奇怪的roomMate.getAnswer("1+1=?", new DoHomeWork() {的哪一行,其实这里new的是DoHomeWork接口的一个匿名内部类。这里我想大家应该自己动脑想想,调用+反调,这个过程是怎么实现的了。至于是否使用匿名内部类是根据具体使用场景决定的。普通类不够直接,匿名内部类的语法似乎也不够友好。开源工具中对回调方法的使用上述匿名内部类的示例才是开源工具中常见到的使用方式。调用roomMate解答问题的方法(传进去自己的引用),roomMate解决问题,回调引用里面包含的回调方法,完成动作。roomMate就是个工具类,“调用”这个方法你传进去两个参数(更多也是一个道理),什么问题,问题解决了放哪,就行了。该“调用”方法根据问题找到答案,就将结果写到你指定放置的位置(作为回调方法的入参)。试想下,“中国好室友”接收的问题是SQL语句,接收的放置位置是我的引用。你解决问题(执行完SQL),将答案(SQL的反馈结果)直接写入我的回调方法里面。回调方法里面可能包括一个个的字段赋值。但是在调用层面隐藏了很多细节的处理。这是回调方法的一个小小的优势。再换句话说,不需要拿到执行完SQL之后的返回结果一个个来赋值。SQL的例子 public static List&Person& queryPerson() {
QueryRunner queryRunner = new QueryRunner(DataSourceSupport.getDataSource());
return queryRunner.query(" select t.name, t.age from person t ", new ResultSetHandler&List&Person&&(){
List list = new ArrayList&Person&();
public List&Person& handle(ResultSet rs) throws SQLException {
while(rs.next()) {
Person person = new Person();
person.setName(rs.getString(0));
person.setAge(rs.getInt(1));
list.add(person);
return list;
回调方法的优势回调方法最大的优势在于,异步回调,这样是其最被广为使用的原因。下面将沿用“中国好室友” 来对回调方法做异步实现。回调接口不用变public interface DoHomeWork {
void doHomeWork(String question, String answer);
为了体现异步的意思,我们给好室友设置了个较难的问题,希望好室友能多好点时间思考。Student student = new Student();
String homework = "当x趋向于0,sin(x)/x =?";
#给学生新建个ask方法,该方法中另开一个线程,来等待回调方法的结果反馈。
student.ask(homework, new RoomMate());
#ask方法如下
public void ask(final String homework, final RoomMate roomMate) {
new Thread(new Runnable() {
public void run() {
roomMate.getAnswer(homework, Student.this);
}).start();
#新开的线程纯粹用来等待好室友来写完作用。由于在好室友类中设置了3秒的等待时间,所以可以看到goHome方法将先执行。
#意味着该学生在告知好室友做作用后,就可以做自己的事情去了,不需要同步阻塞去等待结果。
#一旦好室友完成作用,写入作业本,该现场也就结束运行了。
完整代码public class Student implements DoHomeWork{
public void doHomeWork(String question, String answer) {
System.out.println("作业本");
if(answer != null) {
System.out.println("作业:"+question+" 答案:"+ answer);
System.out.println("作业:"+question+" 答案:"+ "(空白)");
public void ask(final String homework, final RoomMate roomMate) {
new Thread(new Runnable() {
public void run() {
roomMate.getAnswer(homework, Student.this);
}).start();
public void goHome(){
System.out.println("我回家了……好室友,帮我写下作业。");
public static void main(String[] args) {
Student student = new Student();
String homework = "当x趋向于0,sin(x)/x =?";
student.ask(homework, new RoomMate());
public class RoomMate {
public void getAnswer(String homework, DoHomeWork someone) {
if ("1+1=?".equals(homework)) {
someone.doHomeWork(homework, "2");
} else if("当x趋向于0,sin(x)/x =?".equals(homework)) {
System.out.print("思考:");
for(int i=1; i&=3; i++) {
System.out.print(i+"秒 ");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println();
someone.doHomeWork(homework, "1");
someone.doHomeWork(homework, "(空白)");
完结至此回调方法的介绍告一段落。趁着是高考日,表示要跟考生感同身受一下。特意花了整整一个白天的时间写就这篇文章。全文一蹴而就并没有更多时间来修改,可能隐藏着诸多错误,行文也可能不甚通顺,还请各位指正和海涵。 19:24
非回调函数,轮询的方法:,温度计5秒更新自己显示温度,公告板每两秒查看下温度计的温度,如果温度变了就更新公告板上的温度显示回调函数,委托的方法:,公告板把检查的接口暴露给了温度计,委托温度计每次更新温度时直接进行更新所谓的回调函数就是所谓的委托,委托的使用,使得公告板不用关心温度计是否已经更新,只需要将更新的接口暴露给温度计即可。事件的原理就是委托,补个例子:,公告板向温度计注册事件说,你刷新的时候就通知我,且把刷新的温度发给我阿,而这个通知就是温度计调用公告板给的函数onRefresh,即callback来完成。大体上就是这样,例子有不当的地方,欢迎大家指正修改。
不小心撞进来这个问题,本来不想回答,但是@寸志 的回答有些误导:我假设「委托」即Delegate,只有在.Net的世界里Delegate == Callback。是因为在.Net里面,Delegate是唯一能实现Callback的方法。这两个词在其他的语言环境中是不一样。那两段代码有很好的解释callback的这个概念吗?然后回答问题,callback本身和语言无关,它是一种编程模式,存在于所有可以使用function pointer的语言(例如C)或者pass function by reference的语言。简单地说,就是允许当一个函数执行完成后(或者满足一定条件后),执行callback。Callback可以让一个外部的函数,有能力获取和修改一个函数的内部。Callback经常被用作实现Observer Pattern,这也是JS中event相关的部分涉及到许多callback的原因。还有重要的一点就是异步执行(Ajax),或者Node.js的non-blocking,但是这个概念绝对不是仅限于JS的。
好莱坞准则:Don't call me; I'll call you!
回调函数的意思是“把函数A作为参数传递给另一个函数B”。维基百科的解释:a callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time.为什么要这样做呢?为什么不把定义好的函数放在头文件中呢?因为可以作为参数的函数A的名称和实现可以被抽象出来,也就是在写函数B的时候,不需要管函数A叫什么名字,怎么实现,只要函数A的返回类型是一定的就可以了(泛型的话连这个也不需要)。比如某人写了一个画图的库,把具体怎么画留给使用库的人定义。使用库的人就可以自定义画图函数的名称和实现方式。例子(C++):非泛型定义库(library.h)#include &cstdio&
void fill_screen(int (*some_func)(void)) {printf("%d\n",some_func());}
使用库的时候:#include "library.h"
int draw_this_way() {return 0;}
int draw_that_way() {return 1;}
int draw_yet_another_way() {return 2;}
int main() {
fill_screen(&draw_this_way);
fill_screen(&draw_that_way);
fill_screen(&draw_yet_another_way);
编译:g++ callback.cpp -o callback
结果:$./callback
泛型定义库(library.h):# include &iostream&
template&typename ANY_TYPE&
void fill_screen(ANY_TYPE (*some_func)(void)) { std::cout && some_func() && std::endl;}
使用库的时候:#include "library.h"
int draw_this_way() {return 0;}
char draw_that_way() {return 'a';}
bool draw_yet_another_way() {return true;}
int main() {
fill_screen(&draw_this_way);
fill_screen(&draw_that_way);
fill_screen(&draw_yet_another_way);
编译:g++ callback.cpp -o callback
结果:$./callback
补充:委托和回调委托是一种设计模式。意思是A类把自己的工作交给B类完成。简单的委托相当与在A的方法中调用了B的方法。使用委托可以把库的定义和具体使用分开。比如数据库的基本操作是CRUD,但是每个不同数据库具体api不同,对于使用者而言不可能逐个掌握所有数据库的api,所以出现了api的wrapper,用户只用掌握一套CRUD的api就可以使用所有数据库了。在某些不能直接将函数作为参数传递的语言(比如java)中,委托是实现回调功能的一种方式。具体而言,库的作者定义一个接口,在他的方法中调用这个接口,但是把接口的实现留给具体使用的人。在使用的时候,使用者新建一个匿名接口,并且重载要调用的接口方法。 这个过程相当与库的作者将工作通过接口“委托”给了使用者。这个委托的过程相对比较复杂,打个生活中的比方:“领导不但把工作推脱给下属,还要对他们具体怎么干指手画脚。”这里的领导是库的使用者,下属是库的定义,推脱是指调用下属的工作函数,指手画脚是指对工作函数调用的接口给予具体定义。以下是java的例子。定义库 (DrawLibrary.java)public class DrawLibrary {
public interface DrawInterface
int draw();
public static void fillScreen(DrawInterface someObj) {
System.out.println(someObj.draw());
使用库(Graphics.java)public class Graphics {
public static void drawThisWay() {
DrawLibrary.fillScreen( new DrawLibrary.DrawInterface() {
public int draw() {
public static void drawThatWay() {
DrawLibrary.fillScreen( new DrawLibrary.DrawInterface() {
public int draw() {
public static void drawYetAnotherWay() {
DrawLibrary.fillScreen( new DrawLibrary.DrawInterface() {
public int draw() {
public static void main(String[] args) {
drawThisWay();
drawThatWay();
drawYetAnotherWay();
编译:$javac Graphics.java
$java Graphics
这种设计模式经常在事件驱动的设计中看到,比如监听按钮是否被按下等等。
举栗子说吧,你把函数的引用作为参数传入,然后可以在里面调用这个函数,比如你写一个加载脚本的函数,同时可以传入一个函数,可以在加载完脚本时执行相应的函数
有本python 网络编程的书,介绍了twisted库 及其 email 编程。上面说,所谓回调函数,其运行方式是,“你不用调用我,等着我来调用你”。
就是个function pointer."回调函数", 啥事儿一用中文描述就是深奥:)
回调的意思是在你执行某个语句后成功了,再执行你传递进来的function,在做异步处理的时候特别有用。如:$.fn.load=function(urlStr,callback){
url:urlStr,
success:function(data){
$(this).html(data);
callback(data);//执行传递进来的回调函数
})}$('#result').load('ajax/test.html', function() {
alert('我是回调方法.'); });
模块A和B配合做一件事情。模块A清楚在什么时间和地点做这件事情,但不清楚怎么去做;模块B相反,清楚怎么做,但不知道什么时间和地点去做。于是B把“怎么做”封装成了函数;A在合适的时间和地点调用此函数。这个函数就是回调函数。
是设计模式里面template method pattern当template method的数量无限趋近于一的时候的极限
为某一事件or某一时机准备的,注册到系统中,等待系统调用的函数。
就是用函数指针做参数。那个函数指针就是回调函数。
netbios使用中,有ncb_post字段,涉及callback例程。这也是理解callback的好例子。在这里post和callback该怎么翻译好呢?
所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。通常大家说的回调函数是指 编写一个类或类库的人(A) 规定一个 接口(c),然后 你(B) 来实现这个 接口(c),然后把这个实现类的一个对象作为参数传给 (A),(A) 的程序必要时就会通过那个 接口(c) 来调用你编写的函数。咳咳~~有点绕!举个例子:安卓开发 SDK提供的 Button类 需要有个 OnClickLisener 接口 来进行处理点击事件。处理点击事件的代码是由你实现接口完成,当 Button 被点击,Android 系统会执行你编写的事件代码。这个时候其实你实现 OnClickLisener 接口内的 onClick() 就是个回调函数。Java 代码模拟这个例子Android SDK 的 Button:public class Button {
private OnClickLisener onClickL
public interface OnClickLisener {
public void onClick();
public void setOnClickLisener(OnClickLisener onClickLisener) {
this.onClickLisener = onClickL
public void onClick() {
onClickLisener.onClick();
自己的程序:public class Main implements Button.OnClickLisener {
public static void main(String args[]) {
Button button = new Button();
button.setOnClickLisener(new Main());
button.onClick();
public void onClick() {
System.out.println("点击,回调");
博客地址:

我要回帖

更多关于 plus是什么意思 的文章

 

随机推荐