以前看到觉得好,在编译器里写了一遍,这次想找,居然忘了地方,所以还是放这里好
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调用库里预先准备好的函数,但是有些库函数却要求先
* 传给他一个函数,好在合适的时候调用,以完成目标任务,这个被传入的,后又被反调用的函数就称为回调函数。
*/