【Java杂记】回调机制:三种回调方式及代码示例

本文详细介绍了同步调用与异步调用的概念,并通过具体示例解释了回调机制的运作原理,包括基本回调、接口回调及异步回调等不同应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在看回调之前,我们必须明白什么是同步调用与异步调用。这两个概念其实很好理解,同步与异步是相对时间来说的:

  • 同步调用:同一时间只能做一件事
  • 异步调用:同一时间可以做多件事,一般通过以下两种手段实现:
    • 多线程:为需要阻塞的方法单独启动一个线程执行
    • 回调:执行完成后通过回调,通知主线程执行完毕或者获取执行结果

多线程大家一看都能明白,那回调到底是什么呢?

1.回调机制

回调是实现异步调用的一种手段,是为了异步通信服务的,可以细分为以下几种:

1.1 基本回调

基本形式如下:

A对象 ----B.fb(A) -----> B对象  // 调用B的fb()时传入A本身(this)
A对象 <-----A.fa()------ B对象  // B就可以直接调用A,fa()就是回调方法

1.2 接口回调

基于接口回调:若只能给fb()传入A类型那么就是强耦合,所以一般给 fb() 传入的是一个接口,A实现这个接口

AImpl ----B.fb(IA) -----> B对象  // IA是抽象接口,AImpl是IA的实现类
AImpl <-----IA.fa()------ B对象

1.3 异步回调

异步回调就是给B.fb()方法单独起一个线程去执行

  • 使用场景:当A要调用B的某个方法,且该方法会产生阻塞,或耗时较长,则可以将该方法做成异步调用
  • 异步通信:通过回调机制进行通信,执行完后告知A
AImpl ----B.fb(IA) -----> B对象  // B.fb(IA)单独起一个线程执行
AImpl <-----IA.fa()------ B对象

2.代码示例

概念说完了,下面就上代码…

2.1 同步调用

码农(Programmer)现在需要做几件事情:

  1. 敲代码一整天(敲代码)
  2. 将今天工作代码上传到Github上(上传代码)
  3. 备注一下完成日期(记录下完成的日期)

下面我们用程序去实现:程序一共就三个类:

  • Programmer(码农类)
  • Github(Github类 用于保存码农提交的代码)
  • TestDemo(用于测试并显示结果)

如下所示:

public class Programmer {

    public void code(){                       
        System.out.println("coding");      //step1.写代码
        new Github().push();               //step2.提交代码 
        recordToday();                     //step3. 记录的日期
    }

    public void recordToday(){
        System.out.println("i'm done " + new Date());
    }
}
// 只负责上传代码
public class Github {
    public void push(){
        System.out.println("git push");
    }
}
// 让Programmer工作
public class TestDemo {
    public static void main(String args[]){
        Programmer p = new Programmer();
        p.code();
    }
}

执行结果如下:

2.2 基本回调

可否给苦逼程序员一条生路,让他提交代码之后就下班,像记录日期:recodeToday()这种事让Github类去负责。

换句话说,Github类的push()函数执行完后,Github类去调用Programmer类的recodeToday()方法,而不是Programmer自己去调用,略微改动后

// A
public class Programmer {
    public void code(){
        System.out.println("coding");
        new Github().push(this);   // B.fb(this)
        // 这里没有 step3,码农没有自己调用 recordToday()方法.
    }

    // A.fa(),回调方法
    public void recordToday(){
        System.out.println("i'm done " + new Date());
    }
}
// B
public class Github {
    public void push(Programmer p ){   // push的参数多了Programmer类
        System.out.println("git push");
        p.recordToday();    // 执行回调
    }
}

最后执行结果不变

2.3 接口回调

如果现在不只有Programmer了还有Teacher和Student,那GitHub的push方法难道要再重载?最好的办法是push依赖接口

// IA,回调接口
public interface RecodeInterface {
    public void recode();
}
// B
public class Github {
    public void push(RecodeInterface r ){ // 依赖接口
        System.out.println("git push");
        r.recode(); // A.fa(),执行回调
    }
}
// AImpl,实现了接口
public class Programmer implements RecodeInterface{
    public void code(){
         System.out.println("coding");
         new Github().push(this); // B.fb(A)
     }
    
    @Override
    public void recode() { // 回调函数
        System.out.println("Programmer done " + new Date());
    }
}
public class Student {
    public void code(){
        System.out.println("coding");
        new Github().push(new StudentRecodeToday());
    }
	
    // AImpl,也可以单独抽象出一个内部类
    public class StudentRecodeToday implements RecodeInterface{
        @Override
        public void recode() {
            System.out.println("Student done "+ new Date());
        }
    }
}

2.4 异步回调

// IA,回调接口
public interface mycallback {
    void onData(Object message); // 正常处理
    void onError(Exception e); // 异常处理
}
// AImpl,实现了回到接口
public class Client implements mycallback{
    int count=0;
    @Override
    public void onData(Object message) {
        count++;
        System.out.println("received message:"+message.toString());
    }
 
    @Override
    public void onError(Exception e) {
        System.out.println("error!");
    }
    public void send(String message){
        // 异步回调核心!!! 为B.fb(IA)单独启动一个线程
        Thread thread=new Thread(new Server(Client.this,message)); 
        thread.start();
    }
}
// B
public class Server implements Runnable{
    mycallback c;
    Object message;
    public Server(mycallback cl,Object o){
        c=cl;
        message=o;
    }
    @Override
    public void run() {
        try {
            c.onData(message+" after server"); // 执行回调
        }catch (Exception e){
            c.onError(e);
        }
    }
}

启动类

public class Work{
 
    public static void main(String[] args){
        Client c1=new Client();
        c1.send(hello);
        System.out.println("do others...");
    }
}

结果

do others...
received message:hello
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值