如何理解java的回调函数?

article/2025/10/5 16:12:47

对于技术问题,会用是一回事,理解这个技术问题的来龙去脉、设计者当初为什么要设计这个功能、这个技术问题有哪些优势、适用哪些场景又是另外回事了。

前者照猫画虎得其形,后者形神兼备得其意,这也是所谓青铜与王者的区别。

会使用、又能理解已经不易,如果还能表达出来,讲所有人都能看明白就更不容易了。

在软件开发这个行业,回调函数是最常见的功能。在图形界面开发的时候,每一个按钮的点击事件都会用到回调函数。

  • 什么是回调函数?

  • 为什么要用回调函数?

  • 在java中,为什么要用接口来实现回调函数?

这是要弄明白的几个问题!

什么是函数调用?

在弄清楚什么是回调函数之前,先要明白什么函数调用。“调用”的英语叫“call”,翻译过来也叫“打电话”。

打电话无非是沟通、协调、安排一些事情,或者还要得到自己想要的结果。

编程就是对现实的模拟和抽象,一定要理解这句话,下面我们就模拟一下。

我打电话(call)给老婆,问晚上要买点什么菜回家,老婆说买点五花肉回来晚上做回锅肉。我得到了想要的结果,这说明我调用这个函数得到了想要的返回值。

模拟代码:

public String callWife(String 什么菜){//一顿沟通,自行脑补return "五花肉";
}

我给孩子打电话,叮嘱他要完成家庭作业之后才能看电视。这次函数调用没有返回值,就像在函数体里面写了一句"我想你"一样。

模拟代码:

public void callBaby(){System.out.println("I miss you");
}

这些都很好理解,可如果一个电话不能达到自己的目的呢?

我给朋友打电话,问什么时候能约一下其它几个朋友一起吃个饭,他说要先给他们沟通一下什么时候有时间,沟通好了再通知我,具体需要沟通多久也不确定。

这个问题就不是一个电话(一次函数调用)就能解决问题了,需要再打电话回来(callback)才能达到自己的目的。

但此处要记住几个关键点:

  1. 打电话给朋友,相当于我调用了函数callFriend()
  2. 接到朋友的通知,相当于朋友调用了我的一个函数。
  3. 我是这次交互的主体。

什么是回调函数?

在英语中,callback是回电话的意思,而在开发中callback叫回调函数,其实就是回电话的意思,callback这一个单词已经把“回调”的神表达出来了,作为开发者,完全可以按回电话的场景来理解回调函数。

仔细咂摸一下,回电话这个场景与回调函数的使用场景何其像啊!点击一个按钮或链接,然后等待数据的返回和界面的刷新,具体等待多久也不确定,可能0.1秒就响应了,也可能5秒之后才响应,总之,响应时间是不确定的,不能让人一直等着,这不就像等一个回电话的过程吗?

下面我用实际代码模拟上面的沟通过程

这个过程涉及到我和朋友两个实体类,Me类代表我,Friend类代表我的朋友。

因为我要打电话给朋友和接朋友电话通知,所以Me类有三个功能,也叫行为:给朋友打电话,我们用callFriend(Friend)来表示;接到朋友的通知,我们用noticeMe()函数来表示;在给朋友打电话和接朋友电话通知之间的这一段时间,我在忙其它的事情,我们用doOtherthing()函数来表示。

朋友要先给其他小伙伴约时间然后给我打电话,所以Friend类也有个函数order()定义他和其它小伙伴的预约过程,约好时间之后又要给我回电话,所以还要有个参数为Me的对象。

代码如下,这些代码是可以直接运行的,并且用数字对程序的运行顺序做了标记。

Me.java的代码

public class Me {//    给朋友打电话public void callFriend(Friend friend) throws InterruptedException {System.out.println("1、我打电话给朋友,让他去约时间");friend.order(this);doOtherThing();}//    通知我public void noticeMe() {System.out.println("6、我收到了朋友的通知");}//    忙其它的事情去了public void doOtherThing() {System.out.println("3、我去忙其它的事情...");}
}

Friend.java

public class Friend {//和其他小伙伴约好时间后通知我public void order(final Me me) throws InterruptedException {System.out.println("2、朋友接到电话说:我现在就和其他小伙伴约时间,请稍等...");new Thread(new Runnable() {public void run() {try {System.out.println("4、朋友正在电话联系中....");sleep(5000);System.out.println("5、朋友已经约好了,准备给我回电话");me.noticeMe();} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

对这段代码加以说明:

  • 函数中使用线程是为了模拟朋友的沟通过程,在实际应用中多为耗时的操作。
  • “朋友”沟通过程与“我”忙其它事情是并行的,“我”并没有等待他。

最后,写主程序

//测试回调的主类
public class Main {public static void main(String[] args) throws InterruptedException {
//        创建我和朋友的对象Me me = new Me();Friend friend = new Friend();
//        给朋友打电话me.callFriend(friend);}
}

看运行结果
在这里插入图片描述

从结果中可以看出,我联系朋友之后就忙其它事情了,朋友接到电话之后就去沟通,我也不知道他会沟通多久,朋友在沟通完之后通知我,就完事了。

从主程序可以看出,只有我调用了callFriend(),朋友怎么沟通、怎么回电话,我都不关注,他只需要持有“我”对象的引用就行了,需要通知我时,就通过引用调用noticeMe()。

有主动调用过程,也有callBack的过程,这个实例已经展示了回调的全部了,但显然并不完美

试想以下场景:

  • 老板安排给员工一个任务,要求完成工作后通知老板
  • 父母安排你飞机落地后,给他们报个平安。

生活中这样的场景非常多,在实际项目中也是,但是在项目中,我们在每个类中定义一个类似noticeMe()这样的类就不高明了,因为违背了“复用”的编程原则,虽然实现了回调的功能,但并不是真正意义上的回调函数。

所以我们可以对“通知”这一行为进一步抽象,对行为抽象当然要使用接口。

具体代码如下:

/*定义接收通知接口,所有参与者可实现此接口以接收通知*/
public interface CallBack {//参与者可以实现接收通知的细节public void receiveNotice(String friendName);
}

这里有个参数friendName,朋友通知我的时候,可以通过这个参数传递一些信息,比如他的名字。

Me.java实现这个接口后的代码

public class Me implements CallBack{//    给朋友打电话public void callFriend(Friend friend) throws InterruptedException {System.out.println("1、我打电话给朋友,让他去约时间");friend.order(this);doOtherThing();}//    public void noticeMe() {
//
//    }//    忙其它的事情去了public void doOtherThing() {System.out.println("3、我去忙其它的事情...");}//    通知我public void receiveNotice(String friendName) {System.out.println("6、我收到了朋友 -"+friendName+ "- 的通知");}
}

Friend.java做相应的修改后:

public class Friend {//和其他小伙伴约好时间后通知我public void order(final CallBack callBack) {System.out.println("2、朋友接到电话说:我现在就和其他小伙伴约时间,请稍等...");new Thread(new Runnable() {public void run() {try {System.out.println("4、朋友正在电话联系中....");sleep(5000);System.out.println("5、朋友已经约好了,准备给我回电话");callBack.receiveNotice("张三");} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

Main.java的代码不需要调整。

运行结果和前面基本是一致的,我只是增加了一个参数,大家也可以体会一个这个参数带来的便利。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWz7ZZvj-1607071761440)(D:\markdown\前端学习笔记.assets\image-20201204155651918.png)]

多了一个接口的定义,代码好像更多了。但在实际扩展当中却更方便了,比如说,老板要接收员工的通知,老板类实现这个接口就完事了;父母要等待孩子的通知,父母类实现这个接口就可以。换句话说,所有要扩展接收通知的类,只要实现这个接口就具备了接收通知的功能。

这样的好处是代码得到了复用,极大的方便了扩展。

通过接口来实现回调的功能,这才是真正意义上的回调函数。

android中的控件点击,都是用回调函数来实现的,比如Button,View.OnClickListener就是接口,只有一个onClick()函数,类似上面的receiveNotice()函数,只是此处用匿名内部类实现了这个接口。java虚拟机监听着按钮,只要按钮被点击,onClick()就会被调用,而上面的例子是我们在代码中调用的,实质并不区别。

 button.setOnClickListener(new View.OnClickListener() {public void onClick(View v) {//点击后的具体实现}});

这就是我对回调函数的理解,也欢迎与大家就此问题进行交流。


http://chatgpt.dhexx.cn/article/BdwWcLlV.shtml

相关文章

java使用回调函数

java回调函数 回调函数(callback Function),顾名思义就是用来回调的函数。在两个类A、B中,A在调用B接口的同时B也在调用A 回调函数也常用于线程中的异步获取消息。 举个简单的例子,公司中老板分发任务给员工A&#…

java中回调函数的实现

在java的事务中,有时候可能会遇到以下情况,第一步是更新某某表,中间可能要更新不确定的多步,最后一步是更新缓存,结构大致如下: (1)updateA(); (2)updateXX…

什么是java回调函数

回调函数 一:故事背景二:概念三:回调函数的作用四:java中如何进行回调4.1 类图4.2 定义回调接口4.3 实现回调接口4.4 调用方法使用回调函数4.5 Main函数调用4.6 总结描述 五:回调函数的优点5.1 灵活性5.2 解耦性5.3 异…

简单举例JAVA回调函数的实现

来自维基百科的对回调(Callback)的解释:In computer programming, a callback is any executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at a given time. This execut…

java回调函数机制

Java回调函数机制 参考了网上的一些资料,下面也做出一些总结,供初学者了解学习。 一、 概述 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调、异步调用 。 同步调用:一…

java中如何实现回调函数

最近工作需要研究了一会别人写的库,其中充满着各种"回调函数",因此把自己理解给记录下来,存档。 首先我们来看看回调函数 这个概念的具体由来,百度百科的示义如下: 回调函数就是一个通过函数指针调用的函数。…

Java回调函数 + 使用案例

文章目录 前言什么是回调函数第0个版本第1个版本第2个版本第3个版本第4个版本第5个版本第6个版本回头解析前言描述的问题1. MethodIntrospector.selectMethods()2. 抽象类MethodIntrospector3. 方法selectMethods()4. 成员变量USER_DECLARED_METHODS5. 方法doWithMethods()6. d…

Java-回调函数

什么是回调 函数调用可以分为三种模式,串行调用、异步调用、回调。这三种都是日常开发中常见到的方式。 一个方法执行完,再执行下一个,串行逻辑会阻塞线程执行流程,等到所有逻辑执行结束,线程才会结束。 异步执行是…

java回调函数(callBack)

最近有个新同事给我写了个接口,说是用到了回调,我等了半天发现结果才返回回来,把我都整急了。最后我看了他的代码,目瞪口呆。他还信誓旦旦的说没错,按网上的例子来写的。 我一搜,网上例子真一大堆&#xff…

java回调函数的作用以及运用

模块之间总是存在这一定的接口,从调用方式上看,可以分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,也是我们在写程序中经常使用的;回调是一种双向的调用模式,也就是说,被调用的…

Java回调函数理解和应用

#Java回调函数理解和应用 所谓回调:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法,这样子说你是不是有点晕晕的。 在未理解之前,我也是一脸懵逼,等我理解之后&…

java回调函数(全干货)

产生接口回调的场景 产生接口回调的场景很简单,比如A叫B帮忙做一件事,交代完后A去忙别的事,然后B做完这件事之后会通知A, 通知A的这个动作就是接口回调的动作。接口回调 接口回调的意义是通过接口来实现解耦的的前提下调用另一个类的方法,也就是B为A准…

深入理解Java回调函数

废话不多说,像许多网上介绍回调机制的文章一样,我这里也以一个现实的例子开头:假设你公司的总经理出差前需要你帮他办件事情,这件事情你需要花些时间去做,这时候总经理肯定不能守着你做完再出差吧,于是就他…

java 回调函数解读

模块间调用 在一个应用系统中,无论使用何种语言开发,必然存在模块之间的调用,调用的方式分为几种: (1)同步调用 同步调用是最基本并且最简单的一种调用方式,类A的方法a()调用类B的方法b()&…

java中的回调函数

CALLBACK,即回调函数,是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接…

Java回调函数详解

什么是回调函数(CallBack) 在编写程序时,有时候会调用许多API中实现实现的函数,但某些方法需要我们传入一个方法,以便在需要的时候调用我们传入进去的函数。这个被传入的函数称为回调函数(Callback functi…

numpy 数据类型转换

参考NumPy 数据类型 - 云社区 - 腾讯云 首先需要导入numpy模块 import numpy as np 首先生成一个浮点数组 a np.random.random(4) dtype的用法 看看结果信息,左侧是结果信息,右侧是对应的python语句 我们发现这个数组的type是float64,…

javascript学习之数据类型转换

⭐️⭐️⭐️ 作者:船长在船上 🚩🚩🚩 主页:来访地址船长在船上的博客 🔨🔨🔨 简介:资深前端开发工程师,专注前端开发,欢迎咨询交流&#xff0…

【Python入门篇】——Python基础语法(数据类型与数据类型转换)

作者简介: 辭七七,目前大一,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: Python入门,本专栏主要内容为Python的基础语法,Python中的选择循环语句…

Java八种基本数据类型转换

转换规则&#xff1a; 1、八种基本数据类型当中除布尔类型之外剩下的7种类型之间都可以相互转换。 2、小容量向大容量转换&#xff0c;称为自动类型转换&#xff0c;容量从小到大排序(此处没有布尔类型)&#xff1a; byte < short < int < long < float < doub…