回调_回调函数 - CSDN
回调 订阅
回调(huí tiáo 外文名 Retracement),是指在价格上涨趋势中,价格由于上涨速度太快,受到卖方打压而暂时回落的现象。回调幅度小于上涨幅度,回调后将恢复上涨趋势。回调(huí diào 外文名 Callback),是指回调函数,编程术语。 展开全文
回调(huí tiáo 外文名 Retracement),是指在价格上涨趋势中,价格由于上涨速度太快,受到卖方打压而暂时回落的现象。回调幅度小于上涨幅度,回调后将恢复上涨趋势。回调(huí diào 外文名 Callback),是指回调函数,编程术语。
信息
定    义
指在价格上涨趋势中
分    为
回调时间、回调力度、回调量能
中文名
回调
外文名
Retracement
回调编程回调
软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回调机制在不同软件架构中的实现。对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类称为回调类,回调类的对象称为回调对象。对于像C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。
收起全文
精华内容
参与话题
  • 回调(callback)

    千次阅读 多人点赞 2018-10-16 18:47:19
    1、什么是回调 软件模块之间总是存在一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。 同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用。 回调是一种双向...

    http://www.importnew.com/19301.html

    回调的核心就是回调方将本身即this传递给调用方,这样调用方就可以在调用完毕之后告诉回调方它想要知道的信息。

    1、什么是回调

    软件模块之间总是存在一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。

    (1)同步调用:

    在这里插入图片描述
    同步调用是最基本并且最简单的一种调用方式,类A的方法a()调用类B的方法b(),一直等待b()方法执行完毕,a()方法再继续往下走。这种调用方式适用于方法b()执行时间不长的情况,因为b()方法执行时间一长或者直接阻塞的话,a()方法的余下代码是无法执行下去的,这样会造成整个流程的阻塞。

    (2)异步调用:

    在这里插入图片描述
    是一种类似消息或事件的机制,是为了解决同步调用可能出现阻塞,导致整个流程卡住而产生的一种调用方式。类A的方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行,这样无论方法b()执行时间多久,都不会阻塞方法a()的执行。但是这种方式,由于方法a()不等待方法b()执行完成,在方法a()需要方法b()执行结果的情况下(视具体业务而定,有些业务比如启动异步线程发个微信通知、刷新一个缓存这种就没有必要),必须通过一定的方法对方法b()的执行结果进行监听。在Java中,可以使用Future+Callable的方式做到这一点。

    (3)回调:

    在这里插入图片描述

    最后是回调,回调的思想是:

    • 类A的a()方法调用了类B的b()方法
    • 类B的b方法执行完毕主动调用类A的callback()方法

    这样一种调用方式组成了上图,也就是一种双向的调用方式

    回调函数是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。

    在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类称为回调类,回调类的对象称为回调对象。

    例子

    开始之前。先想象一个场景:幼稚园的小朋友刚刚学习了10以内的加法。

    第一章.故事的缘起

    幼师在黑板上写一个式子 “1+1=”,由小明来填空
    由于已经学习了10以内的加法,小明同学可以完全靠自己来计算这个题目,模拟该过程的代码如下:

    public class Student
    {
    	private String name=null;
    	public Student(String name)
    	{
    		this.name=name;
    	}
    	public void setName(String name)
    	{
    		this.name=name;
    	}
    	private int calcADD(int a,int b)
    	{
    		return a+b;
    	}
    	public void fillBlank(int a,int b)
    	{
    		int result=calcADD(a,b);
    		System.out.println(name+"心算:"+a+"+"+b+"="+result);
    	}
    }
    

    小明同学在填空(fillBlank)的时候,直接心算(clacADD)了一下,得出结果是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;
    	}
    	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+16387=",让小明上课之前完成填空,然后又回办公室了。
    小明看着小红再一次递上来的计算机,心生一计:让小红代劳。
    小明告诉小红题目是"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方法就是我们常说的回调函数。

    通过这种方式,可以明显的看出,对于完成老师的填空题这个问题上,小明已经不需要等待到加法做完且结果填写在黑板上才能去跟小伙伴撒欢了,填空这个工作由超级计算器小红来做了。回调的优势已经开始体现了。

    第4章.门口的婆婆

    幼稚园的门口有一个头发花白的老婆婆,每天风雨无阻在那里摆着地摊卖一些快过期的垃圾食品。由于年纪大了,脑子有些糊涂,经常算不清楚自己挣了多少钱。有一天,她无意间听到了小明跟小伙伴们吹嘘自己如何在小红的帮助下与幼师斗智斗勇。于是,婆婆决定找到小红牌超级计算器来做自己的小帮手,并提供一包卫龙辣条作为报酬。小红经不住诱惑,答应了。

    回看一下上一章的代码,我们发现小红牌超级计算器的add方法需要的参数是两个整型变量和一个Student对象,但是老婆婆她不是学生,是个小商贩啊,这里肯定要做修改。这种情况下,我们很自然的会想到继承和多态。如果让小明这个学生和老婆婆这个小商贩从一个父类进行继承,那么我们只需要给小红牌超级计算器传入一个父类的引用就可以啦。

    不过,实际使用中,考虑到java的单继承,以及不希望把自身太多东西暴漏给别人,这里使用从接口继承的方式配合内部类来做。

    换句话说,小红希望以后继续向班里的小朋友们提供计算服务,同时还能向老婆婆提供算账服务,甚至以后能够拓展其他人的业务,于是她向所有的顾客约定了一个办法,用于统一的处理,也就是自己需要的操作数和做完计算之后应该怎么做。这个统一的方法,小红做成了一个接口,提供给了大家,代码如下:

    public interface doJob
    {
    	public void fillBlank(int a,int b,int result);
    }
    

    因为灵感来自帮小明填空,因此小红保留了初心,把所有业务当做填空(fillBlank)来做。

    同时,小红修改了自己的计算器,使其可以同时处理不同的实现了doJob接口的人,代码如下:

    public class SuperCalulator
    {
    	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 class doHomeWork implements doJob
    	{
    		@Override
    		public 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 Seller
    {
    	private String name=null;
    	public Seller(String name)
    	{
    		this.name=name;
    	}
    	public setName(String name)
    	{
    		this.name=name;
    	}
    	public class doHomeWork implements doJob
    	{
    		@Override
    		public 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=56;
    		int b=31;
    		int c=26497;
    		int d=11256;
    		Student s1=new Student("小明");
    		Seller s2=new Seller("老婆婆");
    		
    		s1.callHelp(a,b);
    		s2.callHelp(c,d);
    	}
    }
    

    运行结果如下:

    小明求助小红计算:56+31=87
    老婆婆求助小红算账:26497+11256=37753元

    展开全文
  • 回调的原理、实现与应用

    千次阅读 2018-07-22 09:36:15
    什么回调?维基百科是这样解释的:回调是一段可执行的代码通过参数传递给别一段代码,以期望在一个合适的时间调用这个参数(可执行的代码)。   参考:In computer programming, a callback is a piece of ...

        什么回调?维基百科是这样解释的:回调是一段可执行的代码通过参数传递给别一段代码,以期望在一个合适的时间调用这个参数(可执行的代码)。

     

    参考:In computer programming, 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.

     

    如果你已明白回调或理解上面这一句话,可以漂过,感觉头昏的请往下看。

     

     

    从一个需求开始

     

     

    先不扯淡,直接拿事实说话。假设有这么一个需求:

     

    有一Person类定义如下:

     

     

    struct Person

     

    {

     

        int age;

     

        float weight;

     

        float height;

     

    };

     

     

        现要对Person的一组对象进行排序,但并没有确定根据什么规则来排序,有时需要根据年龄进行排序,有时需要根据身高进行排序,有时可能是根据身高和体重的综合情况来排序,还有可能……

     

     

        你可能会想到这样写,定义三个函数分别根据年龄、体重、身高进行排序:

     

    void SortByAge(Person* persons, int count);

     

    void SortByWeight(Person* persons, int count);

     

    void SortByHeight(Person* persons, int count);

     

        如果要根据身高和体重的综合情况来排序,那你还得再定义一个函数。这样是不是代码冗余且很繁琐?但如果你会用回调,这个问题就会很简单。

     

     

    用回调实现对Person的排序:

     

     

     

    
     
    1. typedef int (*Compare)(const Person&, const Person&);

    2.  
    3. //交换两个元素

    4. void swap(Person* p1, Person *p2)

    5. {

    6. Person p = *p1;

    7. *p1 = *p2;

    8. *p2 = p;

    9. }

    10. //排序(本例中采用冒泡排序)

    11. void PersonSort(Person* persons, int count, Compare pCompare)

    12. {

    13. for (int i = 0; i < count-1; i ++)

    14. {

    15. for (int j = 0; j < count - i -1; j++)

    16. {

    17. if (pCompare(persons[j], persons[j+1]) > 0)

    18. {

    19. swap(persons+j, persons+j+1);

    20. }

    21. }

    22. }

    23. }

     

     

        如果你要根据年龄来进行排序,只要实现一个Compare类型的函数,再调用上面的PersonSort函数就可以实现根据年龄排序的功能。如:

     

     

    
     
    1. int CompareByAge(const Person& p1, const Person& p2)

    2. {

    3. return p1.age - p2.age;

    4. }

    5.  
    6. void TestCallBack()

    7. {

    8. //创建Person的一组对象persons,对象中的各个值为0到100的随机数

    9. srand((unsigned)time(NULL));

    10. Person persons[10];

    11. for(int i = 0; i < 10; i ++)

    12. {

    13. persons[i].age = rand()%100;

    14. persons[i].weight = rand()%100;

    15. persons[i].height = rand()%100;

    16. }

    17. //【todo】

    18. //根据年龄进行排序。

    19. PersonSort(persons, 10, CompareByAge);

    20.  
    21. for(int i = 0; i < 10; i ++)

    22. {

    23. std::cout << persons[i].age << "\t" << persons[i].weight << "\t" << persons[i].height << std::endl;

    24. }

    25. }

     

     

    说明:以上调用TestCallBack函数时需要包含头文件<iostream>、<time.h>

     

     

        这样如果需求发生变更(如要根据每个Person身高和体重的总和来排序),只需求再定义一个Compare类型的函数,而不用再对PersonSort函数做任何改动。如下:

     

     

    
     
    1. int CompareByHeightWeight(const Person& p1, const Person& p2)

    2. {

    3. return (p1.height + p1.weight) - (p2.height + p2.weight);

    4. }

    5.  
    6. void TestCallBack()

    7. {

    8. //创建Person的一组对象persons,对象中的各个值为0到100的随机数

    9. srand((unsigned)time(NULL));

    10. Person persons[10];

    11. for(int i = 0; i < 10; i ++)

    12. {

    13. persons[i].age = rand()%100;

    14. persons[i].weight = rand()%100;

    15. persons[i].height = rand()%100;

    16. }

    17. //【todo】

    18. //根据年龄进行排序。

    19. PersonSort(persons, 10, CompareByHeightWeight);

    20.  
    21. for(int i = 0; i < 10; i ++)

    22. {

    23. std::cout << persons[i].age << "\t" << persons[i].weight << "\t" << persons[i].height << "\t" << persons[i].weight + persons[i].height << std::endl;

    24. }

    25. }

     

     

         C++ STL中的Sort(在<algorithm>头文件中)用的就是这种技术:

     

    template<class RandomAccessIterator>
         void sort(
            RandomAccessIterator first, 
            RandomAccessIterator last
         );
      template<class RandomAccessIterator, class Predicate>
         void sort(
            RandomAccessIterator first, 
            RandomAccessIterator last, 
            Predicate comp
         );
    

    Parameters


    first

    A random-access iterator addressing the position of the first element in the range to be sorted.

    last

    A random-access iterator addressing the position one past the final element in the range to be sorted.

    comp

    User-defined predicate function object that defines the comparison criterion to be satisfied by successive elements in the ordering. This binary predicate takes two arguments and returns true if the two arguments are in order and false otherwise. This comparator function must impose a strict weak ordering on pairs of elements from the sequence. For more information, see Algorithms

     

     

     

        通过上面一个实例的分析,应该对回调有所了解和认识了吧!回调函数说白了就是定义一个函数,然后通过参数传递给另一个函数调用。回调不仅是一种技术,更是一种编程思想,上面是通过回调函数来实现的,但它不仅限于回调函数,也可以用其它的技术实现(如面向对象的实现)。如果想更深入的了解,请看后续的文章。

    展开全文
  • 深入理解:回调函数

    万次阅读 多人点赞 2019-06-21 15:36:09
    关于回调函数到底是什么,已经困扰了我很久了~ 在知乎上看到几位大神的帖子,才恍然大悟 作者:no.body 链接:https://www.zhihu.com/question/19801131/answer/27459821 来源:知乎 作者:常溪玲 链接...

    关于回调函数到底是什么,已经困扰了我很久了~

    在知乎上看到几位大神的帖子,才恍然大悟

    作者:no.body
    链接:https://www.zhihu.com/question/19801131/answer/27459821
    来源:知乎

    作者:常溪玲
    链接:https://www.zhihu.com/question/19801131/answer/13005983
    来源:知乎

    首先要明确的一点是,函数也可以作为函数的参数来传递

    好了,有了这个概念我们来说明回调函数到底是怎么回事

    首先至少要有 3 种类型的函数

    • 主函数:相当于整个程序的引擎,调度各个函数按序执行

    • 回调函数:一个独立的功能函数,如写文件函数

    • 中间函数:一个介于主函数和回调函数之间的函数,登记回调函数,通知主函数,起到一个桥梁的作用

    接下来我们一起来看下示例代码:

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    
    # 回调函数1
    def callback1(x):
        return x * 2 
    
    # 回调函数2
    def callback2(x):
        return x ** 2
    
    # 中间函数
    def middle(x, func):
        return 100 + func(x)
    
    # 主函数
    def main():
    
        x = 1 
    
        a = middle(x, callback1)
        print(a)
    
        b = middle(x, callback2)
        print(b)
    
        c = middle(x, lambda x: x + 2)
        print(c)
    
    main()
    

    运行结果:

    102
    101
    103
    

    代码看懂以后我们接下来分析一下代码的逻辑

    首先我们在主函数执行过程中需要用到一个功能 x * 2,而 callback1 函数就提供这个功能,我们就把这个函数称之为 回调函数(至于为什么要叫“回调函数”,不能叫别的呢?其实这只是人为规定的一个名字。你也可以叫“极客点儿专属函数”,但是到时候你又会问为什么要叫“极客点儿专属函数”,它特么的总的有个名字吧!所以叫“回调函数”就是王八的屁股:规定!)。

    这时候我们的 主函数 要调用它,但是有的时候在开发过程中遇到需要写硬盘的操作,这时候我们为了避免程序的阻塞,就需要用到异步 I/O。就是你自己先写着玩儿,爸爸去干别的事情去了,等你完事儿再来通知我。正是因为这种机制所以得有一个 登记回调函数通知主函数执行完成 的“地方”,这个地方就是 中间函数

    有上述内容我们就可以推导出回调函数执行的流程了:

    1. 主函数需要调用回调函数

    2. 中间函数登记回调函数

    3. 触发回调函数事件

    4. 调用回调函数

    5. 响应回调事件

    回调实际上有两种:阻塞式回调延迟式回调 也可以叫做 同步回调异步回调

    两者的区别在于:

    在阻塞式回调里,回调函数的调用一定发生在主函数返回之前

    在延迟式回调里,回调函数的调用有可能是在起始函数返回之后

    上述示例均为 同步回调,异步需要用到多进程、多线程、协程这些概念,下次有机会再说

    最后用一个例子说明一下到底说明是回调函数:

    你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。

    在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做 触发回调事件,店员给你打电话叫做 调用回调函数,你到店里去取货叫做 响应回调事件

    展开全文
  • Java的回调-由浅入深(保证简单易懂)

    万次阅读 多人点赞 2018-05-05 21:26:37
    转载请注意文章出处:https://blog.csdn.net/fengye454545/article/details/80198446有...看了看网上的回调解释和例子,都那么的绕口,得看半天才能绕回来,其实吧,回调是个很简单的机制。在这里我用简单的语言先来...

    转载请注意文章出处:https://blog.csdn.net/fengye454545/article/details/80198446

    有一段时间没写博客了,可能是因为懒了吧。前几天公司面试有问道java回调的问题,因为这方面也没有太多研究,所以回答的含糊不清,这回特意来补习一下。看了看网上的回调解释和例子,都那么的绕口,得看半天才能绕回来,其实吧,回调是个很简单的机制。在这里我用简单的语言先来解释一下:假设有两个类,分别是A和B,在A中有一个方法a(),B中有一个方法b();在A里面调用B中的方法b(),而方法b()中调用了方法a(),这样子就同时实现了b()和a()两个方法的功能。

    疑惑:为啥这么麻烦,我直接在类A中的B.b()方法下调用a()方法就行了呗。
    解答:回调更像是一个约定,就是如果我调用了b()方法,那么就必须要回调,而不需要显示调用

    一、Java的回调-浅

    我们用例子来解释:小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。一起去吃饭这个事件就是方法a(),小李去洗漱就是方法b()。

    public class XiaoMing {	
       //小明和小李一起吃饭
       public void eatFood() {
          XiaoLi xl = new XiaoLi();
          //A调用B的方法
          xl.washFace();
       }
    
       public void eat() {
          System.out.print("小明和小李一起去吃大龙虾");
       }
    }

    那么怎么让小李洗漱完后在通知小明一起去吃饭呢

    public class XiaoMing {	
       //小明和小李一起吃饭
       public void eatFood() {
          XiaoLi xl = new XiaoLi();
          //A调用B的方法
          xl.washFace();
          eat();
       }
    
       public void eat() {
          System.out.print("小明和小李一起去吃大龙虾");
       }
    }

    不过上面已经说过了这个不是回调函数,所以不能这样子,正确的方式如下

    public class XiaoLi{//小李
       public void washFace() {
    	System.out.print("小李要洗漱");
    	XiaoMing xm = new XiaoMing();
            //B调用A的方法
    	xm.eat();//洗漱完后,一起去吃饭
       }
    }

    这样子就可以实现washFace()同时也能实现eat()。小李洗漱完后,再通知小明一起去吃饭,这就是回调。

    二、Java的回调-中

    可是细心的伙伴可能会发现,小李的代码完全写死了,这样子的场合可能适用和小明一起去吃饭,可是假如小李洗漱完不吃饭了,想和小王上网去,这样子就不适用了。其实上面是伪代码,仅仅是帮助大家理解的,真正情况下是需要利用接口来设置回调的。现在我们继续用小明和小李去吃饭的例子来讲讲接口是如何使用的。

    小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。不同的是我们新建一个吃饭的接口EatRice,接口中有个抽象方法eat()。在小明中调用这个接口,并实现eat();小李声明这个接口对象,并且调用这个接口的抽象方法。这里可能有点绕口,不过没关系,看看例子就很清楚了。

    EatRice接口:

    public interface EatRice {
       public void eat(String food);
    }

    小明:

    public class XiaoMing implements EatRice{//小明
    	
       //小明和小李一起吃饭
       public void eatFood() {
    	XiaoLi xl = new XiaoLi();
    	//A调用B的方法
    	xl.washFace("大龙虾", this);//this指的是小明这个类实现的EatRice接口
       }
    
       @Override
       public void eat(String food) {
    	// TODO Auto-generated method stub
    	System.out.println("小明和小李一起去吃" + food);
       }
    }

    小李:

    public class XiaoLi{//小李
       public void washFace(String food,EatRice er) {
    	System.out.println("小李要洗漱");
            //B调用了A的方法
    	er.eat(food);
       }
    }

    测试Demo:

    public class demo {
       public static void main(String args[]) {
    	XiaoMing xm = new XiaoMing();
    	xm.eatFood();
       }
    }

    测试结果:

    这样子就通过接口的形式实现了软编码。通过接口的形式我可以实现小李洗漱完后,和小王一起去上网。代码如下

    public class XiaoWang implements EatRice{//小王
    	
       //小王和小李一起去上网
       public void eatFood() {
    	XiaoLi xl = new XiaoLi();
    	//A调用B的方法
    	xl.washFace("轻舞飞扬上网", this);
       }
    
       @Override
       public void eat(String bar) {
    	// TODO Auto-generated method stub
    	System.out.println("小王和小李一起去" + bar);
       }
    }

    测试结果:

    三、Java的回调-深

    上面讲的都是同步回调,可是事实上,小李要洗漱后才能吃饭,在小李洗漱的时候,小明是要做自己的事情的,比如他在玩手机,这样子就是异步回调了。而且我们把代码正规化,比如在android点击事件中,你会发现你只要实现View.setOnclickListener(this),即可实现回调,那么像这样子的规范是如何实现的,在这一节里我将会提到。废话少说,先上代码。

    EatRice接口没有变化,这里就省去接口代码展示

    小明:

    public class XiaoMing implements EatRice{
       //小明和小李一起吃饭
       public void eatFood() {
    	XiaoLi xl = new XiaoLi();
    	//A调用B的方法
    	xl.setEatRiceListener(this, "大龙虾");
       }
    
       @Override
       public void eat(String food) {
    	// TODO Auto-generated method stub
    	System.out.print("小明和小李一起去吃" + food);
       }
    }

    小李:

    public class XiaoLi{//小李
    	
       protected EatRice er;
    	
       public void setEatRiceListener(EatRice er, String food) {
    	this.er = er;
    	washFace(food);
       }
    	
       public void washFace(String food) {
    		
    	System.out.print("小李要洗漱");
    		
    	new Thread(new Runnable() {
    			
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			try {
    			    //小李洗漱的同时小明玩手机,开启线程实现异步
    			    play();
    					
    			    Thread.sleep(10000);
    			    System.out.print("10秒后 ");
    			    //B调用A的方法
    			    er.eat(food);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    		                e.printStackTrace();
    			}
    		}
    	}).start();
       }
    	
       //小明玩手机
       public void play() {
    	System.out.println(" 小明要玩手机");
       }
    }

    测试结果:

    首先先打印出 "小李要洗漱 小明要玩手机",过了10秒后打印出“10秒后 小明和小李一起去吃大龙虾”。看到这里相信你对Java的回调有了新的认识吧。


    菜鸟一只,如有不对之处请指出。您的鼓励是我写作的最大动力!

    展开全文
  • 什么是事件回调

    千次阅读 2019-08-08 06:24:14
    第一次听见事件回调是在看netty那本书时书中所提到的,这一次又看到了相关概念,决定进行一个挖掘和学习: 回调的分类:  同步回调  异步回调 同步回调是在事件发生后顺序调用回调接口方法,该种调用在事件...
  • 回调

    2020-10-24 19:48:15
  • 回调的使用

    2018-11-07 10:06:16
    函数调用分直接调用和回调,那什么情况下会想要用回调呢? 工作线程中正在上传一个文件,而UI 线程想要将上传的进度实时显示到进度条中。这个时候我们希望工作线程每更新一次progressValue,UI线程便可以获取到...
  • 彻底理解回调函数,事件,流

    千次阅读 2018-11-29 22:23:04
    回调,是非常基本的概念,尤其在现今NodeJS诞生与蓬勃发展中变得更加被人们重视。很多朋友学NodeJS,学很久一直摸不着门道,觉得最后在用Express写Web程序,有这样的感觉只能说明没有学懂NodeJS,本质上说不理解回调...
  • 什么是回调

    千次阅读 2019-05-31 09:13:02
    回调 就是客户程序C调用服务程序S中的某个方法A 然后S又在某个时候反过来调用C中的某个方法B 对于C来说 这个B便叫做回调方法
  • C语言中函数指针和回调函数的详解

    万次阅读 多人点赞 2019-05-18 23:10:01
    函数指针:指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个...
  • 通俗理解“回调函数”

    万次阅读 多人点赞 2018-06-24 20:42:26
    我们先来看看回调的英文定义:A callback is a function that is passed as an argument to another function and is executed after its parent function has completed。字面上的理解,回调函数就是一个参数,将这...
  • js 彻底理解回调函数

    万次阅读 多人点赞 2017-02-10 13:53:58
    一、前奏在谈回调函数之前,先看下下面两段代码: 不妨猜测一下代码的结果。function say (value) { alert(value); } alert(say); alert(say('hi js.'));如果你测试了,就会发现:只写变量名 say 返回的将会是 say...
  • React中setState回调函数

    万次阅读 2017-07-26 17:20:23
    关于React的setState的回调函数 一般而言,在设置页面某些state的时候,需要先设置好state,然后再对页面的一些参数进行修改的时候,可以使用setState的回调函数。  分析一下区别 不在回调中使用参数,我们在设置...
  • C语言回调函数一个简单的例子

    万次阅读 2013-06-28 17:08:49
    回调函数通俗的解释:  普通函数:你所写的函数调用系统函数,你只管调用,不管实现。  回调函数:系统调用你所写的函数,你只管实现,不管调用。 以下是使用C语言实现回调函数的一个例子: 代码: #include...
  • vue加载完成后的回调函数

    万次阅读 2017-04-24 14:29:45
    var c = new Vue({   el: "#cartoon",   data: data,   mounted: {   alert("vue加载完成");   }  });
  • 微信公众号网页回调授权域名配置

    万次阅读 2017-12-29 16:20:12
    这段时间多次修改公司公众号的回调授权域名,只配置域名(比如:www.baidu.com)不成功,非要在后面加上项目名,才能配置成功。把我烦死了! 加上项目名能配置成功的原因是:把MP_verify_PhkREvZTwSOgr5At.txt文件放在...
  • JS回调函数——简单易懂有实例

    万次阅读 多人点赞 2019-03-26 08:52:23
    初学js的时候,被回调函数搞得很晕,现在回过头来总结一下什么是回调函数。什么是JS?(点击查看) 下面先看看标准的解释: <script language="javascript"> 02 function SortNumber( obj, func ) // ...
  • matlab 回调函数函数的使用方法

    万次阅读 2015-02-05 18:22:53
    一、图形对象的回调函数   1、ButtonDownFcn  当用户将鼠标放到某个对象上,单击鼠标左键时,matlab将调用回调函数  2、GreatFcn  matlab将在创建对象是调用回调函数  3、DeleteFcn  matlab将在删除...
  • 回调函数和钩子函数的区别

    万次阅读 2017-07-05 22:50:28
    在消息处理机制中必不可少的一组CP,即回调和钩子。钩子的概念源于Windows的消息处理机制,通过设置钩子,应用程序可以对所有的消息事件进行拦截,然后执行钩子函数,对消息进行想要的处理方式。接下来是一段js代码...
  • 支付宝支付异步回调的一些问题

    万次阅读 2018-04-27 15:37:33
    做了好多次支付宝支付,还是经常掉坑,现在整理下,作为参考1,关于设置公钥 一定要注意,是“支付宝公钥”,不要填应用公钥,不然就坑了2、关于回调的域名地址 干净些,不要有参数,如:http://*****....
1 2 3 4 5 ... 20
收藏数 1,029,049
精华内容 411,619
关键字:

回调