Java高级技术系列--回调
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java高级技术系列--回调相关的知识,希望对你有一定的参考价值。
1.字面意义上的回调
字面意思上理解回调,就是A调用B,B回过头来再调用A,即是回调.既然是这样,当然就要求A中有B,B中有A.如下:
<li class="alt"><span><span class="keyword">class</span><span> A { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> ask(</span><span class="keyword">final</span><span> B b, </span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> b.answer(<span class="keyword">this</span><span>, question); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> processResult(</span><span class="keyword">final</span><span> String answer) { </span></span></li><li class="alt"><span> System.out.println(answer); </span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">class</span><span> B { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> answer(</span><span class="keyword">final</span><span> A a, </span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (question.equals(</span><span class="string">"What is the answer to life, the universe and everything?"</span><span>)) { </span></span></li><li class=""><span> a.processResult(<span class="string">"42"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SyncObjectCallback { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(</span><span class="keyword">final</span><span> String[] args) { </span></span></li><li class="alt"><span> B b = <span class="keyword">new</span><span> B(); </span></span></li><li class=""><span> A a = <span class="keyword">new</span><span> A(); </span></span></li><li class="alt"><span> </span></li><li class=""><span> a.ask(b, <span class="string">"What is the answer to life, the universe and everything?"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
2.面向对象的回调
上面的写法中,B的对象只在方法中被传递了.实际上,这个B对象后来又调用了A中的方法,它的作用应该不止局限在一个方法中,而应该是A的一个部分.也就是,上面的写法不够"面向对象",让我们来改造一下:
<li class="alt"><span><span class="keyword">class</span><span> A { </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> B b; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> A(</span><span class="keyword">final</span><span> B b) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.b = b; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> ask(</span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.b.answer(</span><span class="keyword">this</span><span>, question); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> processResult(</span><span class="keyword">final</span><span> String answer) { </span></span></li><li class="alt"><span> System.out.println(answer); </span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">class</span><span> B { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> answer(</span><span class="keyword">final</span><span> A a, </span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (question.equals(</span><span class="string">"What is the answer to life, the universe and everything?"</span><span>)) { </span></span></li><li class=""><span> a.processResult(<span class="string">"42"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SyncOOCallback { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(</span><span class="keyword">final</span><span> String[] args) { </span></span></li><li class="alt"><span> B b = <span class="keyword">new</span><span> B(); </span></span></li><li class=""><span> A a = <span class="keyword">new</span><span> A(b); </span></span></li><li class="alt"><span> a.ask(<span class="string">"What is the answer to life, the universe and everything?"</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li>
3.面向接口的回调
上面的两个例子,估计没人会承认也是回调吧.因为并没什么卵用.不过这个流程对于理解回调是很重要的.其实回调真正有用的地方,在于它的"预测"能力.
我们扩展想象一下.假设上面例子中的B,为A提供了很多服务之后突然觉醒,想为更多的对象提供服务,这样一来,B就变成了Server.而且还要制定规则.规则是什么呢,就是要Server提供服务可以,对方一定要有一个recvAnswer接口供Server调用才行,这样Server才能把结果传回给Client.具体如何制定规则呢?通过Interface.如下:
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">interface</span><span> IClient { </span></span></li><li class=""><span> <span class="keyword">void</span><span> recvAnswer(String answer); </span></span></li><li class="alt"><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> Server { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> answer(</span><span class="keyword">final</span><span> IClient client, </span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (question.equals(</span><span class="string">"What is the answer to life, the universe and everything?"</span><span>)) { </span></span></li><li class=""><span> calclating(); </span></li><li class="alt"><span> client.recvAnswer(<span class="string">"42"</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> calclating() { </span></span></li><li class=""><span> <span class="keyword">try</span><span> { </span></span></li><li class="alt"><span> Thread.sleep(<span class="number">5000</span><span>); </span></span></li><li class=""><span> } <span class="keyword">catch</span><span> (InterruptedException e) { </span></span></li><li class="alt"><span> e.printStackTrace(); </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ClientSync </span><span class="keyword">implements</span><span> IClient { </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> Server server; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> ClientSync(</span><span class="keyword">final</span><span> Server server) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.server = server; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> ask(</span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.server.answer(</span><span class="keyword">this</span><span>, question); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="annotation">@Override</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> recvAnswer(</span><span class="keyword">final</span><span> String answer) { </span></span></li><li class=""><span> System.out.println(answer); </span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SyncInterfaceCallback { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(</span><span class="keyword">final</span><span> String[] args) { </span></span></li><li class="alt"><span> Server server = <span class="keyword">new</span><span> Server(); </span></span></li><li class=""><span> ClientSync client = <span class="keyword">new</span><span> ClientSync(server); </span></span></li><li class="alt"><span> client.ask(<span class="string">"What is the answer to life, the universe and everything?"</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li>
注意,接口IClient实际上应该是属于Server端的,它是由Server制定的,需要Client来实现的接口,虽然看上去它跟Client很近.
为什么说有"预测"能力呢?想象另一个场景.Server现在是一个底层服务,这个底层服务知道迟早有一天会有高层服务来讨要数据,但是数据如何向上传递呢?底层可以承诺,只有你实现IClient接口,我就会调用其中的recvAnswer方法,把数据传上来.现在底层也可以调用高层的方法,算是有"预测"能力吧?
4.异步回调
上面的调用都是同步的.假设Server计算结果需要较长的时间,你一定希望它能在一个单独的线程中被执行,这是就可以把ask方法的调用用线程包装一下:
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ClientAsync </span><span class="keyword">implements</span><span> IClient { </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> Server server; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> ClientAsync(</span><span class="keyword">final</span><span> Server server) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.server = server; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> ask(</span><span class="keyword">final</span><span> String question) { </span></span></li><li class="alt"><span> <span class="keyword">new</span><span> Thread(</span><span class="keyword">new</span><span> Runnable() { </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> run() { </span></span></li><li class="alt"><span> server.answer(ClientAsync.<span class="keyword">this</span><span>, question); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> }).start(); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="annotation">@Override</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> recvAnswer(</span><span class="keyword">final</span><span> String answer) { </span></span></li><li class=""><span> System.out.println(answer); </span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> AsyncInterfaceCallback { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(</span><span class="keyword">final</span><span> String[] args) { </span></span></li><li class="alt"><span> Server server = <span class="keyword">new</span><span> Server(); </span></span></li><li class=""><span> ClientAsync client = <span class="keyword">new</span><span> ClientAsync(server); </span></span></li><li class="alt"><span> client.ask(<span class="string">"What is the answer to life, the universe and everything?"</span><span>); </span></span></li><li class=""><span> System.out.println(<span class="string">"asked ! waiting for the answer..."</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
5.线程池异步回调
每次建立新的线程耗费资源巨大,为了重用线程,使用线程池管理异步调用,这时候就要求Client不仅要实现IClient接口,还要同时是一个任务,才能被线程池执行,如下:
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ClientRunnable </span><span class="keyword">implements</span><span> IClient, Runnable { </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> Server server; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> String question; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> id; </span></span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> ClientRunnable(</span><span class="keyword">final</span><span> Server server, </span><span class="keyword">final</span><span> String question, </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> id) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.server = server; </span></span></li><li class=""><span> <span class="keyword">this</span><span>.question = question; </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.id = id; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="annotation">@Override</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> recvAnswer(</span><span class="keyword">final</span><span> String answer) { </span></span></li><li class=""><span> System.out.println(<span class="string">"clinet "</span><span> + </span><span class="keyword">this</span><span>.id + </span><span class="string">" got answer: "</span><span> + answer); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> run() { </span></span></li><li class="alt"><span> server.answer(ClientRunnable.<span class="keyword">this</span><span>, </span><span class="keyword">this</span><span>.question); </span></span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li>
<li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> ThreadpoolCallback { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">void</span><span> main(</span><span class="keyword">final</span><span> String[] args) { </span></span></li><li class="alt"><span> ExecutorService es = Executors.newCachedThreadPool(); </span></li><li class=""><span> </span></li><li class="alt"><span> Server server = <span class="keyword">new</span><span> Server(); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < </span><span class="number">100</span><span>; i++) { </span></span></li><li class=""><span> ClientRunnable cr = <span class="keyword">new</span><span> ClientRunnable(server, </span><span class="string">"What is the answer to life, the universe and everything?"</span><span>, </span></span></li><li class="alt"><span> i); </span></li><li class=""><span> es.execute(cr); </span></li><li class="alt"><span> System.out.println(<span class="string">"client "</span><span> + i + </span><span class="string">" asked !"</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> es.shutdown(); </span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li>
至此,我们就实现了线程池异步回调.
本文出自 “梦里不知身是客” 博客,请务必保留此出处http://greatestrabit.blog.51cto.com/11375247/1757340
以上是关于Java高级技术系列--回调的主要内容,如果未能解决你的问题,请参考以下文章