Java 是如何利用接口避免函数回调的方法

 更新时间:2018年02月12日 09:34:28   作者:Wray Zheng  
本篇文章主要介绍了Java 是如何利用接口避免函数回调的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

一、引言

在许多编程语言中,都有函数回调这一概念。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 中,函数回调需要利用反射机制来完成,易出错、效率低,而使用接口可以让代码的逻辑更加清晰、运行效率更高、也更便于调试。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解SpringMVC @RequestBody接收Json对象字符串

    详解SpringMVC @RequestBody接收Json对象字符串

    这篇文章主要介绍了详解SpringMVC @RequestBody接收Json对象字符串,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • JAVA将中文转换为拼音简单实现方法

    JAVA将中文转换为拼音简单实现方法

    拼音转换是中文处理的常见需求,TinyPinyin、HanLP、pinyin4j是常用的本地拼音转换库,各有特点,开发者可根据具体需求选择合适的拼音转换工具,需要的朋友可以参考下
    2024-10-10
  • java设计模式Ctrl C和Ctrl V的原型模式详解

    java设计模式Ctrl C和Ctrl V的原型模式详解

    这篇文章主要为大家介绍了java设计模式Ctrl C和Ctrl V的原型模式详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • SpringBoot集成支付宝沙箱支付的实现示例

    SpringBoot集成支付宝沙箱支付的实现示例

    本文主要介绍了SpringBoot集成支付宝沙箱支付的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java中String的JdbcTemplate连接SQLServer数据库的方法

    Java中String的JdbcTemplate连接SQLServer数据库的方法

    这篇文章主要介绍了Java中String的JdbcTemplate连接SQLServer数据库的方法,在研发过程中我们需要与其他系统对接的场景,连接SQLServer拉取数据,所以就用jdbc连接数据库的方式连接外部数据源,需要的朋友可以参考下
    2021-10-10
  • 基于Spring Boot的Logback日志轮转配置详解

    基于Spring Boot的Logback日志轮转配置详解

    本篇文章主要介绍了基于Spring Boot的Logback日志轮转配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • 解决@RequestBody接收json对象报错415的问题

    解决@RequestBody接收json对象报错415的问题

    这篇文章主要介绍了解决@RequestBody接收json对象报错415的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java中jqGrid 学习笔记整理——进阶篇(二)

    Java中jqGrid 学习笔记整理——进阶篇(二)

    这篇文章主要介绍了Java中jqGrid 学习笔记整理——进阶篇(二)的相关资料,需要的朋友可以参考下
    2016-04-04
  • springboot 整合sentinel的示例代码

    springboot 整合sentinel的示例代码

    本文主要介绍了springboot 整合sentinel的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 如何基于SpringWeb MultipartFile实现文件上传、下载功能

    如何基于SpringWeb MultipartFile实现文件上传、下载功能

    在做项目时,后端经常采用上传文件组件MultipartFile,下面这篇文章主要给大家介绍了关于如何基于SpringWeb MultipartFile实现文件上传、下载功能的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-07-07

最新评论