Java 是如何利用接口避免函数回调的方法
作者:Wray Zheng 发布时间:2023-11-11 10:14:00
一、引言
在许多编程语言中,都有函数回调这一概念。C 和 C++ 中有函数指针,因此可以将函数作为参数传给其它函数,以便过后调用。而在 JavaScript 中,更是将函数回调发挥到了极致,各种事件的处理,特别是异步事件,基本都靠函数回调来完成。
在 Java 中,同样可以实现函数回调。虽然没有函数指针,但 Java 可以通过反射机制来获得一个类的方法,将其以 java.lang.reflect.Method 类型参数传递给其它函数,然后通过 Method 对象的 invoke 方法来调用该函数。
尽管如此,这种方式的调用步骤相对繁琐、执行效率低、难以调试。在 Java 中,有比函数回调更加优雅的机制,那就是接口。
二、为什么需要函数回调
函数回调,实际上是延迟实现某些功能的一种方式。
如果我们事先知道程序应该执行哪些操作,那么完全不需要函数回调,直接在编程时实现即可。
但很多时候,在编写代码时,特别是写工具类、功能库或框架时,实现的是相对通用和抽象的功能,而具体场景下的功能则由使用这些类的开发者来实现。
函数回调,可以解决这种事先不知道具体实现的情况。
排序函数的例子
举例来说,当我们要实现一个通用的排序函数时,事先并不知道其他开发者会用该函数来对哪些类型的元素进行排序,也就不知道以何种标准来判断这些元素的偏序(大小)关系。
因此,可以要求其他开发者在使用排序函数时,必须提供一个比较函数 compare,这样我们就可以用 compare 比较待排序元素的大小,而无需事先知道元素是什么类型,也无需知道 compare 的具体实现。
这里 compare 函数对于排序函数来说,就是回调函数。
伪代码表示如下:
//通用的排序函数
void sort(Object[] array, Method compare) {
//利用 compare 函数比较 array 中元素的大小关系
//以便对 array 进行排序
}
//由调用者实现具体的比较函数
int compare(Object a, Object b) {
//比较元素a、b,并返回大小关系
}
异步处理函数的例子
再比如说,当我们编写一个异步处理函数时,事先不知道其他开发者在处理完成时要进行哪些操作,因为这些操作只有在特定场景下使用该函数时才能知道。
于是可以要求开发者在使用该函数时,提供一个回调函数 callback。这样我们在编写异步处理函数时,就可以调用 callback 函数来进行一些收尾的工作,而无需事先知道这些收尾的工作是什么。
伪代码表示如下:
//异步处理函数
void asynProcess(Method callback) {
//执行异步任务
callback();
}
//由调用者实现具体的回调函数
void callback() {
//异步处理完成后要进行的操作
}
三、用接口代替函数回调
上面我们提到,之所以使用函数回调这一方式,是因为 事先不知道某些功能的具体实现,因此将具体实现留给其他开发者完成。
有没有觉得这句话仿佛在描述 Java 的接口?接口(interface)是一组方法的抽象定义,具体实现由实现该接口的类来完成。
所以,利用面向对象和接口这两个特性,可以代替函数回调。
我们以上面举的两个例子来说明接口是如何代替函数回调的。
排序函数
用接口实现排序函数,不再要求开发者在使用该排序函数时提供回调函数 compare,而是要求开发者确保待排序元素实现了 Comparable 接口,基于“待排序元素已经实现了 Comparable 接口“这一前提下,我们无需知道待排序元素的类型,就可以实现排序功能。
//通用的排序函数
void sort(Object[] array) {
//利用 Comparable 接口的 compareTo 方法
//比较元素的大小,以便对 array 进行排序。
}
//由排序函数定义的接口
public interface Comparable {
public int compareTo(Object other);
}
//由调用者实现 Comparable 接口
public class Element implements Comparable {
@Override
public int compareTo(Object other) {
//判断当前 Element 与 other 的大小关系
//并返回两者的关系
}
}
异步处理函数
使用接口来实现异步处理函数时,不要求开发者提供回调函数 callback,而是要求提供一个实现了指定接口的对象,这很好地体现了 Java 面向对象的思想。相比提供一个函数,一个对象包含的信息更丰富,使用起来更加灵活。但本质上,该异步处理函数还是利用接口来完成收尾工作的。
//异步处理函数
void asynProcess(ActionListener al) {
//执行异步任务
al.actionPerformed();
}
//由异步处理函数定义的接口
public interface ActionListener {
void actionPerformed();
}
//由调用者实现 ActionListener 接口
public class ExtraTask implements ActionListener {
@Override
public void actionPerformed() {
//异步处理函数执行完成时,需要进行的额外工作
}
}
//调用异步处理函数
public static void main(String[] args) {
asynProcess(new ExtraTask());
}
四、总结
回调方式可以总结为:实现一个通用函数 func,在具体场景中调用这个通用函数时,调用者需要提供合适的回调函数 callback。通用函数 func 利用该回调函数,完成具体场景中的任务。
而接口实现的方式则是:实现一个通用函数 func,在具体场景中调用这个通用函数时, * 作的对象需要自己实现合适的接口,通用函数会利用该接口,完成具体场景中的任务。
利用函数回调或者接口,都可以解决事先不知道具体实现的情况。函数回调方式传递的是函数,而接口方式传递的是实现了该接口的对象。
在 Java 中,函数回调需要利用反射机制来完成,易出错、效率低,而使用接口可以让代码的逻辑更加清晰、运行效率更高、也更便于调试。
来源:http://www.codebelief.com/article/2018/02/java-how-to-use-interface-to-avoid-function-callback


猜你喜欢
- 本文实例为大家分享了安卓Button按钮的四种点击事件,供大家参考,具体内容如下第一种:内部类实现 1.xml里面先设置Button属性&l
- 昨天有朋友在公众号发消息说看不懂await,async执行流,其实看不懂太正常了,因为你没经过社会的毒打,没吃过牢饭就不知道自由有多重要,没
- 上传临时文件被删除引起报错的解决1.前言在项目中使用到了SpringBoot的上传实现了一个excel导入功能,上线后稳得一批,但突然有一天
- 前言关系复杂度一、直接插入排序基本思想:将新的数据插入已经排好的数据列中。将第一个和第二个数排序,构成有序数列然后将第三个数插进去,构成新的
- 概述:堆排序是利用构建“堆”的方法确定具有最大值的数据元素,并把该元素与最后位置上的元素交换。可将任意一个由n个数据元素构成的序列按照(a1
- 概述模板方法模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。那么什么是模板方法呢?我们看下模板方法的定义。一个具体方法而非
- 本文实例为大家分享了Android实现View滑动效果的具体代码,供大家参考,具体内容如下一、View的滑动简介View的滑动是Androi
- 概述RocketMQ 支持发送延迟消息,但不支持任意时间的延迟消息的设置,仅支持内置预设值的延迟时间间隔的延迟消息;预设值的延迟时间间隔为:
- 一、导入相关jar包,pom依赖如下: <dependency> <groupId>org
- 工厂模式定义:提供创建对象的接口。为何使用工厂模式工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java
- 首先对Servlet上传文件的简单理解此前,Servlet本身没有对文件上传提供直接的支持,一般需要使用第三方框架来实现,这样就比较麻烦不过
- 还原背景大家都做过b-s架构的应用,也就是基于浏览器的软件应用。现在呢有个场景就是FE端也就是前端工程是前后端分离的,采用主流的前端框架VU
- C#中Invoke的用法()invoke和begininvoke 区别一直对invoke和begininvoke的使用和概念比较混乱,这两天
- 在1.zip中增加一张新图片StorageFile jpg = await KnownFolders.PicturesLibrary.Get
- 欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demo
- Android存储方式有很多种,在这里所用的存储方式是SharedPreferrences,其采用了Map数据结构来存储数据,以键值的方式存
- 关于数据绑定Xamarin 单向、双向绑定Xaml绑定C#代码绑定在此之前,几段 伪代码 帮助像我一样菜的同学入门。。。假如说,有两个控件,
- 现在一些app通常会在头部放一个广告位,底部放置一行小圆圈指示器,指示广告位当前的页码,轮播展示一些图片,这些图片来自于网络。这个广告位ba
- 下面介绍的这个版本搭配是我研究好久好久才跑通的,这在我的电脑上是一组可行的配置,如果你使用了同样的配置跑不通,那可能是环境中某一部分还是有不
- 通过程序自动的读取其它网站网页显示的信息,类似于爬虫程序。比方说我们有一个系统,要提取BaiDu网站上歌曲搜索排名。分析系统在根据得到的数据