回调函数在JavaScript或者其他语言里可能更常见,比如事件处理之类的,但Java里可能不太一样,因为Java没有函数指针,不过可以用接口或者匿名类来实现类似的功能。
回调函数的核心是“在某个事件发生后被调用的函数”。比如,当某个任务完成时,调用预先定义好的方法。在Java中,通常通过接口来实现,因为接口定义了一组方法,然后由其他类来实现这些方法,并在需要的时候调用。
一、回调的核心概念
类比理解:老师布置作业,学生完成后通知老师批改。
老师:定义回调接口(布置作业和批改的方法)
学生:完成任务后调用老师的方法(回调)
二、同步回调
1 定义回调接口
// 老师的工作接口(回调规范)
interface Teacher {
void assignHomework(); // 布置作业
void checkHomework(); // 检查作业(回调方法)
}
2 学生类(触发回调)
class Student {
// 学生接收老师对象(回调接口)
public void doHomework(Teacher teacher) {
System.out.println("学生: 开始写老师布置的作业...");
System.out.println("学生: 作业写完了,通知老师检查!");
teacher.checkHomework(); // 关键步骤:触发回调
}
}
3 具体实现回调
public class Main {
public static void main(String[] args) {
Teacher mrWang = new Teacher() {
@Override
public void assignHomework() {
System.out.println("王老师: 今天的作业是《Java回调机制》");
}
@Override
public void checkHomework() {
System.out.println("王老师: 开始批改学生提交的作业...");
}
};
mrWang.assignHomework(); // 老师布置作业
new Student().doHomework(mrWang); // 学生做完后触发回调
}
}
4 运行结果
王老师: 今天的作业是《Java回调机制》
学生: 开始写老师布置的作业...
学生: 作业写完了,通知老师检查!
王老师: 开始批改学生提交的作业...
三、异步回调(模拟耗时操作)
当任务需要较长时间(如网络请求),使用多线程异步回调:
class StudentAsync {
public void doHomeworkAsync(Teacher teacher) {
new Thread(() -> {
System.out.println("学生: 正在努力写作业(需要5秒)...");
try {
Thread.sleep(5000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("学生: 终于写完了,异步通知老师!");
teacher.checkHomework(); // 在子线程中回调
}).start();
}
}
// 使用示例
public static void main(String[] args) {
Teacher mrLi = new Teacher() { /* 同样实现接口 */ };
new StudentAsync().doHomeworkAsync(mrLi);
System.out.println("主线程: 不阻塞,继续处理其他事情...");
}
四、使用Lambda简化代码
Java 8+ 支持Lambda表达式,简化接口实现:
Teacher msZhang = () -> System.out.println("张老师: 作业是Lambda表达式!");
Student student = new Student();
student.doHomework(msZhang);
五、回调的核心优势
解耦:学生类不依赖具体老师,只认接口
扩展性:更换老师实现不影响学生逻辑
事件驱动:适用于按钮点击、网络响应等场景
六、对比直接调用
传统做法:学生直接调用mrWang.checkHomework()
→ 学生类必须知道具体老师类,耦合度高
回调模式:学生通过接口调用teacher.checkHomework()
→ 只需遵守接口规范,与具体实现解耦