回调函数理解的整理(某知乎大神写的)

本文通过一个关于学生和好舍友的故事,详细解释了回调函数的概念,并展示了回调函数在不同场景下的应用,包括接口方式的回调、匿名内部类回调以及异步回调。文章深入探讨了回调函数的优势及其实现方法,旨在帮助读者更好地理解和运用这一重要的编程概念。

以前看到觉得好,在编译器里写了一遍,这次想找,居然忘了地方,所以还是放这里好


package com.example.callback;


public class CallBack {


}
/*
 * 通过中国好室友的例子来理解回调函数的概念
 */


//有个学生要写作业,写作业的方法是现成的,但是需要作业作为入参,怎么获取作业才是关键
/*
 * 1.有个学生
 * Student student=new Student();
 * 2.该学生有写作业这个动作需要执行
 * student.doHomeWork(someHomeWork)
 * 3.注意到这个写作业的动作是需要得到入参“作业”后才能进行的,所以给这个同学new了个简单的题目做
 *  String aHomeWork="1+1=?";
student.doHomeWork(aHomeWork);
 */


public class Student{
public void doHomeWork(String homeWork){
System.out.println("作业本");
if("1+1=?".equals(homeWork)){
System.out.println("作业:"+homeWork+"答案"+"2");
}else{
System.out.println("作业:"+homeWork+"答案"+"不知道~~");
}
}

public static void main(String[] args){
Student student=new Student();
String aHomeWork="1+1=?";
student.doHomeWork(aHomeWork);
}
}


//室友帮忙写作业 第一阶段 还是自己写
/*
 * 1.因为有室友帮忙写,所以在doHomeWork动作里面,就不需要有逻辑判断的代码,因为舍友会直接把答案写入,所以,改为
 *   student.doHomeWork(aHomeWork,theAnswer)
 * 2.上例中的作业的动作支持传人“作业”和“答案”,有这两个,就说明能做好作业了
 *   其中aHomeWork作业是已知的,但是theAnswer却是室友提供的
 * 3.室友怎么才能提供答案呢,最简单的是,室友这个对象直接提供一个传入作业,传出答案的方法,这样该同学就可以直接调用了
 * RoomMate roomMate=new RoomMate()
 * String theAnswer=roomMate.getAnswer(aHomeWork)
 * student.doHomeWork(aHomeWork,theAnswer)
 * 
 */


public class Student{
public void doHomeWork(String homework,String answer){
System.out.println("作业本");
if(answer!=null){
System.out.println("作业:"+homeWork+"答案"+answer);
}else{
System.out.println("作业:"+homeWork+"答案"+"(空白)");
}
}

public static void main(String[] args){
Student student=new Student();
String aHomeWork="1+1=?";
RoomMate roomMate=new RoomMate();
String theAnswer=roomMate.getAnswer(aHomeWork);
student.doHomeWork(aHomeWork,theAnswer);
}

}


public class RoomMate{
public String getAnswer(String Homework){
if("1+1=?".equals(Homework)){
return "2";
}else{
return null;
}
}

}
//作业还是得自己写,太麻烦,能不能让好舍友“直接调用我的做作业方法”帮我把答案写好,把作业做完
//好舍友第二阶段,让舍友直接把作业写了


/*
 * 1.待解决的作业
 * String aHomeWork="1+1=?"
 * 2.室友写出答案‘
 * String theAnswer=roomMate.getAnswer(aHomeWork)
 * 3.该同学调用,自己把答案写到作业本上(也即是这个步骤不给调用了)
 * student.doHomeWork(aHomeWork,theAnswer)
 * 4.做作业必须得调用这个方法,而根据需求这个方法必须由室友调用。很显然,该室友得保持一个该同学的引用,才能正常调用
 * 室友说,那你在调用getAnswer方法的时候,除了传人作业,还需要把自己的引用放在里面,这样我做完了。直接调用你的做作业方法就好了
 * roomMate.getAnswer(aHomeWork,student)
 * 
 * 让室友直接把作业写了,就已经体现了回调的意思
 * 1.学生调用室友的替写作业方法,注册了题目和自己的引用,室友的替写作业方法被调用,则会根据题目完成作业后,再回调该同学的写作业方法,完成作业
 * 2.类A调用类B的方法b(传入相关的信息),类B的方法在执行完后,会将结果写到(再回调)类A的方法a,完成动作(其实a 就是传说中的回调方法啦)
 * 3.调用,回调
 */


public class Student{
public void doHomeWork(String homework,String answer){
System.out.println("作业本");
if(answer!=null){
System.out.println("作业:"+homeWork+"答案"+answer);
}else{
System.out.println("作业:"+homeWork+"答案"+"(空白)");
}
}
public static void main(String[] args){
Student student=new Student();
String aHomeWork="1+1=?";
RoomMate roomMate=new RoomMate();
roomMate.getAnswer(aHomeWork,student);
}
}


public class RoomMate{
public void getAnswer(String homework,Student student){
if("1+1=?".equals(homework)){
student.doHomeWork(homework,"2");
}else{
student.doHomeWork(homework,null);
}
}
}


//接口方式的回调
/*
 * 因为在调用的时候直接把自己的对象传进去,很不安全,所以最常规的“调用,回调”实现,是使用接口作为引用传入调用的方法里面
 * 
 * 当我们研究RoomMate类的getAnswer方法的时候,会发现,这个方法的用途是来解决学生提出的问题,答案是通过学生的doHomeWork方法回调回去的。
 * 那假设工人也有这个问题,该室友该怎么解决呢,再开个方法,专门接收工人的引用作为传参?当然不用,只要你这个引用包含了doHomeWork方法,那么无论你是工人,警察,还是学生,直接调用getAnswer()放大就能解决你提的问题
 * 
 * 至此的思路,所有对象要有同一个方法,所以自然而然的引出接口的概念,只要这些对象都实现了某个接口就行了,这个接口的引用,仅仅规定来做作业的那个方法长什么样。这样工人继承了该接口,那么就有了默认继承的做作业方法,工人在把自己的引用给室友的时候,这个室友就不需要改动
 * 任何代码,直接得出答案,完成任务
 * 
 * 所以创建一个接口,专门规定,需要哪些东西(问题和答案),就能做作业
 * 
 * public interface DoHomeWork{
 * void doHomeWork(String question,String answer);
 * }
 * 
 * 改动下中国好舍友的解答方法,任意一个实现了DoHomeWork的接口的someone.都拥有doHomeWork(String question,String answer)的方法,这个方法就是上面已经提到的“回调方法”,someone先调用下好室友的getAnswer方法,把问题和自己传进来(此为调用),好室友解答完后,调用默认
 * 提供的方法,写完作业
 * 
 * 因为是以接口作为参数类型的约定,在普通对象向上转型后将只暴露接口描述的那个方法,别人获取到这个引用,也只能使用这个(回调)方法,所以可以解决安全隐患
 */


public interface DoHomeWork{
void doHomeWork(String question,String answer);
}


public class Worker implements DoHomeWork{


@Override
public void doHomeWork(String question, String answer) {
// TODO Auto-generated method stub
System.out.println("作业本");
if(answer!=null){
System.out.println("作业:"+question+"答案"+answer);
}else{
System.out.println("作业:"+question+"答案"+"(空白)");
}
}

public static void main(String[] args){
Worker worker=new Worker();
String question="1+1=?";
new RoomMate().getAnswer(question,worker);
}

}


public class RoomMate{
public void getAnswer(String homework,DoHomeWork someone){
if("1+1=?".equals(homework)){
someone.doHomeWork(homework,"2");
}else{
someone.doHomeWork(homework,null);
}
}
}


//回调常规使用之匿名内部类
/*
 * 我们之前已经定性,中国好室友RoomMate类拥有接受任何人问问题挑战的潜质,自从好室友出名后,
 * 有个不知道什么工作(类型)的人也来问问题。反正只要实现了回调接口,好室友都能调用你默认的回调方法
 * 
 */


public interface DoHomeWork{
void doHomeWork(String question,String answer);
}
public class RoomMate{
public void getAnswer(String homework,DoHomeWork someone){
System.out.println("作业本");
if("1+1=?".equals(homework)){
someone.doHomeWork(homework,"2");
}else{
someone.doHomeWork(homework,null);
}
}

public static void main(String[] args){
RoomMate roomMate=new RoomMate();
roomMate.getAnswer("1+1=?",new DoHomeWork(){
public void doHomeWork(Sring question,String answer){
System.out.println("问题"+question+"答案"+answer);
}
});
}
}




//回调方法最大的优势是可以异步回调,这也是回调被广为使用的原因
/*
回调的接口不变
public interface DoHomeWork{
void doHomeWork(String question,String answer);
}


为了体现异步的思想,我们给好舍友设置了个较难的题目,来等待回调方法的结果反馈
Student student=new Student()
String homework="当x趋向于0,sin(x)/x=?"
给学生新建个ask方法,该方法中另开一个线程,来等待回调方法的结果反馈
Student.ask(homework,new RoomMate())
ask方法如下

public void ask(final String homework,final RoomMate roomMate){
new Thread(new Runnable(){

public void run(){
roomMate.getAnswer(homework,Student.this);
}
}).start();
goHome();
}

新的线程纯粹是用来等待好室友写完作业,由于在好室友设置了三秒的等待时间,所以可以看到goHome()方法先执行,
意味着该学生告诉好室友做作业后,就自己做自己的事情去了,不需要同步阻塞等待结果
一旦好舍友完成应用,写入作业本,该现场就结束运行了
*/
public interface DoHomeWork{
void doHomeWork(String question,String answer);
}


public class Student implements DoHomeWork{
public doHomeWork(String question,String answer){
System.out.println("作业本");
if("1+1=?".equals(homework)){
someone.doHomeWork(homework,"2");
}else{
someone.doHomeWork(homework,null);
}
}

public void ask(final String homework,final RoomMate roomMate){
new Thread(new Runnable(){

public void run(){
roomMate.getAnswer(homework,Student.this);
}
}).start();

goHome();
}

public void goHome()
{
System.out.println("我回家了。。。。好室友,帮我写下作业");
}
public static void main(String[] args){
Student student=new Student();
String homework="当x趋向于0,sin(x)/x=?";
student.ask(homework,new RoomMate());
}
}


public class RoomMate{
public void getAnswer(String homework,DoHomeWork someone){
if("1+1=?".equals(homework)){
someone.doHomeWork(homework,"2");
}else if("当x趋向于0,sin(x)/x=?".equals(homework)){
System.out.println("...思考");
for(int i=1;i<=3;i++){
System.out.println(i+"seconds");
try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println();
someone.doHomeWork(homework,"1");
}else{
someone.doHomeWork(homework,"(空白)");
}
}
}


//至于回调函数在系统中的应用
/*
 * 当程序跑起来的时候,一般情况下,应用程序会市场通过API调用库里预先准备好的函数,但是有些库函数却要求先
 * 传给他一个函数,好在合适的时候调用,以完成目标任务,这个被传入的,后又被反调用的函数就称为回调函数。
 */


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值