回调函数

1 模块间调用

模块间调用分为三种

  1. 同步调用:A类的方法a()直接调用B类的b()方法。
  2. 异步调用:类A的方法方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行。
  3. 回调:类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;
    }
}

总结

其实回调也是普通的调用,本质同一个引用,被不同的类调用。回调通常和匿名内部类一起来用使得看起来有些复杂,如果能拆开来看的话就会好理解。回调的作用可以理解为将动作和动作开始的时间分离:在自己的类中只定义应该怎么做,然后把这个类的引用给另一个类的方法去调用。

posted on 2018-05-06 01:02  吼吼吼的吼  阅读(991)  评论(0编辑  收藏  举报

导航