网站留言发送到qq邮箱,自己做网站地址,建设网站都需要准备什么,wordpress头像自定义前几天看了一下Spring的部分源码#xff0c;发现回调机制被大量使用#xff0c;觉得有必要把Java回调机制的理解归纳总结一下#xff0c;以方便在研究类似于Spring源码这样的代码时能更加得心应手。 注#xff1a;本文不想扯很多拗口的话来充场面#xff0c;我的目的是希望… 前几天看了一下Spring的部分源码发现回调机制被大量使用觉得有必要把Java回调机制的理解归纳总结一下以方便在研究类似于Spring源码这样的代码时能更加得心应手。 注本文不想扯很多拗口的话来充场面我的目的是希望以最简明扼要的语言将Java回调的大概机制说清楚。好了言归正传。 一句话回调是一种双向调用模式什么意思呢就是说被调用方在被调用时也会调用对方这就叫回调。“If you call me, i will call back”。 不理解没关系先看看这个可以说比较经典的使用回调的方式 class A实现接口InA ——背景1class A中包含一个class B的引用b ——背景2class B有一个参数为InA的方法test(InA a) ——背景3A的对象a调用B的方法传入自己test(a) ——这一步相当于you call me然后b就可以在test方法中调用InA的方法 ——这一步相当于i call you back 是不是清晰一点了下面再来看一个完全符合这个方式模板的例子 PS这个例子来源于网络由于这个例子表现的功能极度拉风令我感觉想想出一个超越它的例子确实比较困难所以直接搬过来 Java代码 //相当于接口InA public interface BoomWTC{ //获得拉登的决定 public benLaDengDecide(); // 执行轰炸世贸 public void boom(); } //相当于class A public class At$911 implements BoomWTC{//相当于【背景1】 private boolean decide; private TerroristAttack ta;//相当于【背景2】 public At$911(){ Date nownew Date(); SimpleDateFormat myFmt1new SimpleDateFormat(yy/MM/dd HH:mm); this.dicede myFmt.format(dt).equals(01/09/11 09:44); this.tanew TerroristAttack(); } //获得拉登的决定 public boolean benLaDengDecide(){ return decide; } // 执行轰炸世贸 public void boom(){ ta.attack(new At$911);//class A调用class B的方法传入自己的对象相当于【you call me】 } } //相当于class B public class TerroristAttack{ public TerroristAttack(){ } public attack(BoomWTC bmw){——这相当于【背景3】 if(bmw.benLaDengDecide()){//class B在方法中回调class A的方法相当于【i call you back】 //lets go......... } } } 现在应该对回调有一点概念了吧。 可是问题来了对于上面这个例子来说看不出用回调有什么好处直接在调用方法不就可以了为什么要使用回调呢 事实上很多需要进行回调的操作是比较费时的被调用者进行费时操作然后操作完之后将结果回调给调用者。看这样一个例子 Java代码 //模拟Spring中HibernateTemplate回调机制的代码 interface CallBack{ public void doCRUD(); } public class HibernateTemplate { public void execute(CallBack action){ getConnection(); action.doCRUD(); releaseConnection(); } public void add(){ execute(new CallBack(){ public void doCRUD(){ System.out.println(执行add操作...); } }); } public void getConnection(){ System.out.println(获得连接...); } public void releaseConnection(){ System.out.println(释放连接...); } } 可能上面这个例子你不能一眼看出个所以然来因为其实这里A是作为一个内部匿名类存在的。好不要急让我们把这个例子来重构一下 Java代码 interface CallBack{ //相当于接口InA public void doCRUD(); } public class A implements CallBack{//【背景1】 private B b;//【背景2】 public void doCRUD(){ System.out.println(执行add操作...); } public void add(){ b.execute(new A());//【you call me】 } } public class B{ public void execute(CallBack action){ //【背景3】 getConnection(); action.doCRUD(); //【i call you back】 releaseConnection(); } public void getConnection(){ System.out.println(获得连接...); } public void releaseConnection(){ System.out.println(释放连接...); } } 好了现在就明白多了吧完全可以转化为上面所说的回调使用方式的模板。 现在在来看看为什么要使用回调取得连接getConnection();是费时操作A希望由B来进行这个费时的操作执行完了之后通知A即可即所谓的i call you back。这就是这里使用回调的原因。 在网上看到了一个比喻觉得很形象这里借用一下 你有一个复杂的问题解决不了打电话给你的同学你的同学说可以解决这个问题但是需要一些时间那么你不可能一直拿着电话在那里等你会把你的电话号码告诉他让他解决之后打电话通知你。回调就是体现在你的同学又反过来拨打你的号码。 结合到前面所分析的你打电话给你同学就是【you call me】你同学解决完之后打电话给你就是【i call you back】。 怎么样现在理解了吧 ---------------------------------以下为更新---------------------------------- 看了有些朋友的回帖我又思考了一下感觉自己之前对回调作用的理解的确存在偏差。 下面把自己整理之后的想法共享一下如果有错误希望指出多谢 先说上面这段代码本来完全可以用模板模式来进行实现 Java代码 public abstract class B{ public void execute(){ getConnection(); doCRUD(); releaseConnection(); } public abstract void doCRUD(); public void getConnection(){ System.out.println(获得连接...); } public void releaseConnection(){ System.out.println(释放连接...); } } public class A extends B{ public void doCRUD(){ System.out.println(执行add操作...); } public void add(){ doCRUD(); } } public class C extends B{ public void doCRUD(){ System.out.println(执行delete操作...); } public void delete(){ doCRUD(); } } 如果改为回调实现是这样的 Java代码 interface CallBack{ public void doCRUD(); } public class HibernateTemplate { public void execute(CallBack action){ getConnection(); action.doCRUD(); releaseConnection(); } public void add(){ execute(new CallBack(){ public void doCRUD(){ System.out.println(执行add操作...); } }); } public void delete(){ execute(new CallBack(){ public void doCRUD(){ System.out.println(执行delete操作...); } }); } public void getConnection(){ System.out.println(获得连接...); } public void releaseConnection(){ System.out.println(释放连接...); } } 可见摒弃了继承抽象类方式的回调方式更加简便灵活。不需要为了实现抽象方法而总是继承抽象类而是只需要通过回调来增加一个方法即可更加的直观简洁灵活。这算是回调的好处之一。 下面再给出一个关于利用回调配合异步调用的很不错的例子 回调接口 Java代码 public interface CallBack { /** * 执行回调方法 * param objects 将处理后的结果作为参数返回给回调方法 */ public void execute(Object... objects ); } 消息的发送者 Java代码 /** * 这个类相当于你自己 */ public class Local implements CallBack,Runnable{ private Remote remote; /** * 发送出去的消息 */ private String message; public Local(Remote remote, String message) { super(); this.remote remote; this.message message; } /** * 发送消息 */ public void sendMessage() { /**当前线程的名称**/ System.out.println(Thread.currentThread().getName()); /**创建一个新的线程发送消息**/ Thread thread new Thread(this); thread.start(); /**当前线程继续执行**/ System.out.println(Message has been sent by Local~!); } /** * 发送消息后的回调函数 */ public void execute(Object... objects ) { /**打印返回的消息**/ System.out.println(objects[0]); /**打印发送消息的线程名称**/ System.out.println(Thread.currentThread().getName()); /**中断发送消息的线程**/ Thread.interrupted(); } public static void main(String[] args) { Local local new Local(new Remote(),Hello); local.sendMessage(); } public void run() { remote.executeMessage(message, this); //这相当于给同学打电话打完电话之后这个线程就可以去做其他事情了只不过等到你的同学打回电话给你的时候你要做出响应 } } 消息的接收者 Java代码 /** * 这个类相当于你的同学 */ public class Remote { /** * 处理消息 * param msg 接收的消息 * param callBack 回调函数处理类 */ public void executeMessage(String msg,CallBack callBack) { /**模拟远程类正在处理其他事情可能需要花费许多时间**/ for(int i0;i1000000000;i) { } /**处理完其他事情现在来处理消息**/ System.out.println(msg); System.out.println(I hava executed the message by Local); /**执行回调**/ callBack.execute(new String[]{Nice to meet you~!}); //这相当于同学执行完之后打电话给你 } } 由上面这个例子可见回调可以作为异步调用的基础来实现异步调用。 转载于:https://www.cnblogs.com/smilesmile/p/3833385.html