【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 动态绑定(多态)的特性。
    可以针对不同的业务场景,使用不同的代码结构。
    如果业务更专注于人群的 “操作”,那么建议使用间接回调;如果业务更专注于人群类别的辨析,那么建议使用直接回调。

总结

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

参考博客

https://www.cnblogs.com/winifredaf/p/10016871.html
https://blog.csdn.net/lc545126483/article/details/79954612

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值