回调函数
1 模块间调用
模块间调用分为三种
- 同步调用:A类的方法a()直接调用B类的b()方法。
- 异步调用:类A的方法方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行。
- 回调:类A在a()中调用类B的b()方法,b()方法中又调用了在类A中定义的方法。
2 回调
2.1 其实回调也是一种普通的调用。我们在一个类中定义好行为,而具体什么时候调用,交给另一个类的方法,其实就是传递引用。我们先来看下下面的调用
public class CallbackTest {
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
Callback callback = new Callback();
Foo foo = new Foo();
foo.test(callback); // 将callback引用传入
}
}
class Callback { // 普通的类
public void call(String name) { // 参数具体是什么是调用的时候指定的
System.out.println("call: " + name); // 声明行为
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello"); // 具体什么时候执行
}
}
在上面的代码中,我们分别有两个普通的类Callback和Foo,Foo的test方法接受一个Callback对象,并调用Callback对象的call方法。这很好理解。
2.2 我们同样可以写一个Callback的子类,来实现自己的方法。
public class CallbackTest {
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
Callback callback = new MyCallback(); // 使用子类覆盖
Foo foo = new Foo();
foo.test(callback); // 将callback引用传入
}
}
class Callback { // 普通的类
public void call(String name) {
System.out.println("call: " + name);
}
}
class MyCallback extends Callback {
public void call(String name) {
System.out.println("my call: " + name); // 声明自己的行为
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello");
}
}
上述代码中Callback更通常的写法应该是写成接口或者抽象类。上述代码还可以有一个变形,就是让public类继承或实现Callback,如
public class CallbackTest extends Callback{
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
// Callback callback = new MyCallback();
Foo foo = new Foo();
foo.test(this); // 将自己传进去
}
public void call(String name) {
System.out.println("my call: " + name); // 定义行为
}
}
class Callback { // 普通的类
public void call(String name) {
System.out.println("call: " + name);
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello");
}
}
2.3 使用匿名类。上述代码可以简化成使用匿名内部类
public class CallbackTest {
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
// Callback callback = new MyCallback();
Foo foo = new Foo();
foo.test(new Callback() { // 匿名内部类,通常写法Callback是一个接口,不过普通类也可以
public void call(String name) {
System.out.println("my call: " + name);
}
}); // 将callback引用传入
}
}
class Callback { // 普通的类
public void call(String name) {
System.out.println("call: " + name);
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello");
}
}
2.4 匿名内部类可以访问外部类的方法,因此我们可以将具体的实现放到外部类中。
public class CallbackTest {
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
// Callback callback = new MyCallback();
Foo foo = new Foo();
foo.test(new Callback() {
public void call(String name) {
myCall(name); // 调用外部类的方法
}
}); // 将callback引用传入
}
// 具体要进行的行为
public void myCall(String name) {
System.out.println("my call: " + name);
}
}
class Callback { // 普通的类
public void call(String name) {
System.out.println("call: " + name);
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello");
}
}
2.5 回调函数可以加上状态。上面的Callback都是无状态的,我们可以给Callbakc加上状态,然后再调用的时候设置Callback状态,这样通过Callback的引用就可以执行任务执行的状态,类似java中的Future。
public class CallbackTest {
public static void main(String[] args) {
CallbackTest callbackTest = new CallbackTest();
callbackTest.test();
}
public void test() {
Callback callback = new MyCallback(); // 使用子类覆盖
Foo foo = new Foo();
foo.test(callback); // 将callback引用传入
while (!callback.complete) { // 通过callback的引用可以知道调用的状态,是不是项java中的Future?
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("not complete");
}
System.out.println("complete");
}
}
class Callback { // 普通的类
public boolean complete = false; // 包含状态
public void call(String name) {
System.out.println("call: " + name);
}
}
class MyCallback extends Callback {
public void call(String name) {
System.out.println("my call: " + name); // 声明自己的行为
}
}
class Foo { // 普通的类
public void test(Callback callback) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
callback.call("hello");
callback.complete = true;
}
}
总结
其实回调也是普通的调用,本质同一个引用,被不同的类调用。回调通常和匿名内部类一起来用使得看起来有些复杂,如果能拆开来看的话就会好理解。回调的作用可以理解为将动作和动作开始的时间分离:在自己的类中只定义应该怎么做,然后把这个类的引用给另一个类的方法去调用。