java回调
来源:互联网 发布:易建联nba生涯数据 编辑:程序博客网 时间:2024/06/07 05:41
一:背景
why-为什么需要回调关于什么是回调网上很多,但是很少有从为什么需要回调开始,所以下面从基本调用开始到最后为什么使用回调
1. 同步调用
A类中a()去调用B类的b()。
一个最大的问题,阻塞,在a()方法执行了2行代码在去调用b()方法,但是b()执行了耗时的操作,那么a()只能等到b()执行完,在能去执行或许的代码,产生了整个流程的阻塞。
所以这个只适合非耗时操作,也是项目中用到最多的方法。
2.异步调用
很多时候A类中a()去调用B类的b()需要耗时操作,就必须异步调用了
a()中开启一个新的线程执行b()这样,无论b()操作多长时间,都不会影响a()的正常执行,有利就有弊,这里如果b()是执行一些下载,刷新和a()没交互的方法不会有任何问题,但是如果a()需要b()提供一些参数,那么就不可以实现了。这里就需要回调了。
二:回调
what-什么是回调
上图:A类中a()调用了b(),在b()执行完操作后又去调用了A类中的callback()通知最后的结果。
回调的理解:简单的说,A类中a()中调用了B类中b(),在一段时候后b()执行完操作,然后把自己结果作为一个或多个参数传递个A使用的过程。
三:写回调
how-如何写回调
1.基本版本
情况是这样的,学生小明要做一个加法,但是太笨了,不会!
就找到了小红,小红非常聪明,俗称超级计算机。
小明说“小红你帮我计算下1+1等于几,然后直接帮我写到作业本上,拜拜!”
然后小明跑了,小红在2s后做完,写出了最后结果。
ok
这就是最基本的回调。
小明(Student )告诉小红 (SuperCalculator )2个数字
小红 (SuperCalculator )计算完成后,在小明的本子上写出答案 (调用Student 的 fillBlank())
>public class Student { private String name = null; public Student(String name) { this.name = name; } public void callHelp(int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result); }}>public class SuperCalculator { //只能接收单一学生类,没有扩展性 public void add(int a, int b, Student xiaoming) { int result = a + b; xiaoming.fillBlank(a, b, result); }}>public class Test {scxda public statica void main(String[] args) { int a = 11; int b = 12; Student s = new Student("小明"); s.callHelp(a, b); }}
具体代码如上面,很简单,没毛病。但是,没有扩展性,小红现在只能为小明(Student)服务,如果老师来找小红,帮忙计算一下2+2等于几就不可以了,因为小红,只能接收单一的Student类,不接受Teacher。如何办
2.升级版本
增加一个父类,doJob,Student Teacher 都继承了doJob这个父类,这样小红可以愉快的算加法了,无论是谁只要是doJob的子类就可以找小红帮忙了。但是这是最后结果吗?不是的!
public abstract class doJob{ public abstract void fillBlank(int a, int b, int result);}public class Teacher extends doJob { private String name = null; public Teacher(String name) { this.name = name; } public void callHelp(int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "要求小红计算:" + a + " + " + b + " = " + result); }}public class Student extends doJob { private String name = null; public Student(String name) { this.name = name; } public void callHelp(int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result); }}public class SuperCalculator { //优扩展性,所有实现接口的类都可以传递进入 public void add(int a, int b, doJob d) { int result = a + b; d.fillBlank(a, b, result); }}public class Test { public static void main(String[] args) { int a = 11; int b = 12; int c = 100; Student s = new Student("小明"); Teacher t = new Teacher("Teacher"); s.callHelp(a, b); t.callHelp(a,c); }}
3.在次升级版本
几乎一样,但是有一个核心的区别接口
没错,这才是最常见的回调版本。
小明,和老师没有同一个父类,他们只有一个共同的接口 doJob
why?
接口和父类实现的效果一样,但是有几个很大的区别
1.降低耦合性,为了一个简单的加法功能,就去继承一个父类,太浪费了,java是单继承的,只能有一个父亲,为了一个功能就去叫爸爸,他浪费太奢侈了。父类和子类的亲密度太高了,这里没有这个需求(一般多个子类有一些公共的方法参数才会需要去继承同一个父类的)
2.减少暴露的数据,如果使用了一个父类,那么小红在计算的时候不仅仅回调fillBlank一个方法,还可以知道很多别的方法,例如小明的零食在哪了,老师喜欢那个小朋友了
3.为了后续的扩展:如果现在增加需求算乘法2*2,但是小红不会怎么办,都继承了一个父类,那只能去修改这个父类,新增一个方法,然后找到小王,让他帮忙计算,瞬间复杂了很多,很多没有关系的人在了一起。而且每增加一次都要修改一次,太麻烦了。
所以,这里最简单的就是接口了:说白了,接口能做的父类都能做,但是没有必要,这里只是需要一个契约!
接口就是这个契约
小红只需要吧计算好的结果给fillBlank()就可以了
小明,老师也只是需要知道fillBlank()给了什么参数就可以,别的情况,双方都不需要,也没有必要知道!
public interface doJob{ void fillBlank(int a, int b, int result);}public class Student implements doJob { private String name = null; public Student(String name) { this.name = name; } public void callHelp(int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "求助小红计算:" + a + " + " + b + " = " + result); }}public class Teacher implements doJob { private String name = null; public Teacher(String name) { this.name = name; } public void callHelp(int a, int b) { new SuperCalculator().add(a, b, this); } public void fillBlank(int a, int b, int result) { System.out.println(name + "要求小红计算:" + a + " + " + b + " = " + result); }}public class SuperCalculator { //优扩展性,所有实现接口的类都可以传递进入 public void add(int a, int b, doJob d) { int result = a + b; d.fillBlank(a, b, result); }}public class Test { public static void main(String[] args) { int a = 11; int b = 12; int c = 100; Student s = new Student("小明"); Teacher t = new Teacher("Teacher"); s.callHelp(a, b); t.callHelp(a,c); }}
四:Android中的应用
回调应用非常多,android中最常见的一个应用就是各种点击事件,只要有交互的界面,都回用到View的回调。
核心都是一样onClick
1系统view内部增加一个OnClickListener接口包含一个 onClick方法。
2 定义回调接口的成员变量
public OnClickListener mOnClickListener;
3view中增加一个setOnClickListener() 设置回调接口对象成员变量
4外部的activity需要实现点击效果的控件,去调用setOnClickListener方法(所有控件最终的父类View,所以全部控件都是具有setOnClickListener方法),需要一个参数View中定义接口的实现,为了方便一般都是使用匿名内部类了。
5最后执行,在用户点击一个控件后,最终会执行performClick方法,执行mOnClickListener的onClick方法。
android中接口的好处,假设有2个button,1号点击后去刷新界面,2号点击后去下载内容。这些系统是不知道的,系统只会通知什么时候点击了,点击后的操作就是具体程序员完成了,各司其职,降低耦合度。
这个流程完成,下面是简化后的源码,看明白后对接口的理解可以更上一层了。
public class ViewT { /* * 定义回调接口的成员变量 */ public OnClickListener mOnClickListener; /** * 声明回调接口 * Interface definition for a callback to be invoked when a view is clicked. */ public interface OnClickListener { /** * Called when a view has been clicked. * * @param v The view that was clicked. */ void onClick(ViewT v); } /** * 设置回调接口对象成员变量 * Register a callback to be invoked when this view is clicked. If this view is not * clickable, it becomes clickable. * * @param l The callback that will run */ public void setOnClickListener(OnClickListener l) { mOnClickListener = l; } /** * 调用回调接口对象中的方法 * Call this view's OnClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @return True there was an assigned OnClickListener that was called, false * otherwise is returned. */ public boolean performClick() { mOnClickListener.onClick(this); return true; }} //这里就是我们一般写的方法了,写一个匿名内部类实现接口,在系统调用onClick方法时候接受到消息在处理了 ttview.setOnClickListener(new ViewT.OnClickListener() { @Override public void onClick(ViewT v) { //接受到 模拟的ViewT对象,可以做处理了 } });
五:总结
这就是回调从无到有到强大的过程,这里只是写了一部分,太多例子文章都是最后一步。
很长时间都想不明白为什么要这样,最近收集不少文章整理后发现,要从根上面理解一个概念才能更好的学习理解了。
参考文章:
http://www.importnew.com/19301.html
http://www.cnblogs.com/xrq730/p/6424471.html
http://www.jianshu.com/p/3f86b7949f20
- java回调
- java回调
- java 回调
- JAVA:回调
- java 回调
- java回调
- java 回调
- Java 回调
- java回调
- Java 回调
- Java回调
- Java 回调
- Java 回调
- Java回调
- java回调
- java 回调
- Java回调
- java回调
- 从零自学Hadoop(11):Hadoop命令上
- DFS:100. Same Tree
- 32位汇编的基本框架
- 2017-9-23(servlet登录和448. Find All Numbers Disappeared in an Array)
- MySQL 索引失效问题分析
- java回调
- [栈] brackets 括号序列
- ACM-ICPC北京赛区(2017)网络赛-题目9 : Minimum(线段树)
- 第五节第一大特性-封装
- Windows Server2008部署python爬虫环境
- Longest Substring Without Repeating Characters
- Lucene和solr
- Ubuntu 16.04设置root用户登录图形界面
- JAVA注册功能步骤