您的位置 首页 java

Java 回调函数

前言

最近在复习一些编程的基础知识,发现回调函数这个东西用起来很方便。

于是就研究了一下Java是如何实现真正意义上的回调函数。

直接调用与间接调用

在理解回调函数之前,我们需要先来理解在 c/c++ 中,什么是直接调用,什么是间接调用。

直接调用

在函数A的函数体里,通过书写函数B的函数名来调用之,使内存中对应函数B的代码得以执行。

这里,A称为“主叫函数”(Caller),B称为“被叫函数”(Callee)。

间接调用

在函数A的函数体里并不出现函数B的函数名,而是通过指向函数B的函数指针p,来使内存中属于函数B的代码片断得以执行。

两者比较而言,间接调用的灵活性更强,因为传入的参数只是一个函数的指针,所以我们可以在函数中随意改变指针指向的地址,从而调用不同的函数。

Java的回调函数

在 Java 中,回调函数是指:

A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法。我们也可以实现 直接调用 间接调用

为了更好的理解,借用一位博主的例子,来向进行说明。

比如,现在许多人遇到计算问题都会借助计算器。那我们就模拟一个场景,现在有一个计算器可以处理加法运算。学生群体和销售员群体,都需要借助这个计算器进行计算,并进行写结果的操作,在计算器计算期间,学生和销售员都会进行休息(多线程异步计算)。

直接调用

Java 中的直接调用是,直接通过函数入参的对象引用来调用函数。并且,我们可以通过继承的方式,来进行一个优化的写法。

父类:Idiot

 public class Idiot {
//求助计算器算数
    public void callHelp(final int a, final int b) {
        //异步计算
        new Thread(new Runnable() {
            public void run() {
                new SuperCalculator().add(a, b, Idiot.this);
            }
        }).start();
        System.out.println("Idiot 在休息……");
    }
//写的操作
    public void fillBlank(int result) {
        System.out.println("idiot:" + result);
    }
}  

子类1:Student

 public class Student extends Idiot {
    @Override
    public void callHelp(final int a, final int b) {
        //异步计算
        new Thread(new Runnable() {
            public void run() {
                new SuperCalculator().add(a, b, Student.this);
            }
        }).start();
        System.out.println("student 在休息……");
    }
    @Override
    public void fillBlank(int result) {
        System.out.println("student:" + result);
    }
}  

子类2:Seller

 public class Seller extends Idiot {
    @Override
    public void callHelp(final int a, final int b) {
        //异步计算
        new Thread(new Runnable() {
            public void run() {
                new SuperCalculator().add(a, b, Seller.this);
            }
        }).start();
        System.out.println("seller 在休息……");
    }
    @Override
    public void fillBlank(int result) {
        System.out.println("seller:" + result);
    }
}  

计算器

 public class SuperCalculator {
    public void add(int a, int b, Idiot idiot) {
        //回调函数(写操作),通过父类进行调用。
        idiot.fillBlank(a + b);
    }
}  

测试类

 public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Seller seller = new Seller();
        student.callHelp(10,10);
        seller.callHelp(20,20);
    }
}  

在这个直接回调的写法中,我们只需要用使用者的视角专注业务类型,而不需要关心中间做了什么。也就是说在测试的过程中,我们并没有 “写操作” 的痕迹,这一过程在计算器中被回调。这是一个非常方便的写法。

间接调用

Java 中的间接调用是使用接口来完成的。在这里,我们将 “写操作” 这一行为抽象为一接口,那么计算器就不需要关心是被哪个群体使用的,而更加关心业务本身,让代码解耦。

DoJod接口

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

Student

 public class Student {
    public class doHomeWork implements DoJob {
        public void fillBlank(int a, int b, int result) {
            System.out.println("student 计算结果:" + result);
        }
    }
    public void callHelp(final int a, final int b) {
        new Thread(new Runnable() {
            public void run() {
                //调用superCalculator的函数
                new SuperCalculator().add(a, b, new Student.doHomeWork());
            }
        }).start();
        System.out.println("student 在休息……");
    }
}  

Seller

 public class Seller {
    public class doCalculate implements DoJob {
        public void fillBlank(int a, int b, int result) {
            System.out.println("seller 计算结果:" + result);
        }
    }
    public void callHelp(final int a, final int b) {
        new Thread(new Runnable() {
            public void run() {
                //调用superCalculator的函数
                new SuperCalculator().add(a, b, new doCalculate());
            }
        }).start();
        System.out.println("seller 在休息……");
    }
}  

计算器

 public class SuperCalculator {
//屏蔽了调用的具体对象,只对业务接口负责。
    public void add(int a, int b, DoJob job) {
        //回调函数(写操作),通过接口进行调用。
        job.fillBlank(a, b, a + b);
    }
}  

测试类

 public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Seller seller = new Seller();
        student.callHelp(10, 10);
        seller.callHelp(20, 20);
    }
}  
Java 回调函数

两者对比

其实两者谁优谁劣不好评判,两者的不同主要在于:

直接回调通过父类对象的引用调用函数,利用 Java 向上转型(**继承**)的特性。

而间接回调通过接口进行函数的调用,利用 Java 动态绑定(**多态**)的特性。

可以针对不同的业务场景,使用不同的代码结构。

借用上方例子,如果业务更专注于人群的 “操作”,那么建议使用间接回调;如果业务更专注于人群类别的辨析,那么建议使用直接回调。

总结

说到底,回调函数到底有什么用?

注意到之前,所有的计算都是使用的多线程异步计算,也就是说,我们不需要去监听计算器什么时候得出结果,而只需要在计算完成时,对群体的函数进行回调就行了,感觉是不是很方便哈哈。

参考博客

文章来源:智云一二三科技

文章标题:Java 回调函数

文章地址:https://www.zhihuclub.com/176879.shtml

关于作者: 智云科技

热门文章

网站地图