• 回调函数


    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;
        }
    }
    

    总结

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

  • 相关阅读:
    如何设置nginx日志格式来查看负载分担结果
    Nginx缓存使用官方教程及常见问题解答
    nginx缓存和flask_cache
    flask_wtf/wtforms几个坑点,先简单记此
    maven-dependency-plugin插件的使用
    maven+jenkins+jmeter性能测试:maven把项目依赖拷贝到项目指定位置
    sudo:抱歉,您必须拥有一个终端来执行 sudo 解决办法;ssh执行sudo命令的方法;给用户增加sudo免密权限
    innerHTML引起IE的内存泄漏
    innerHTML与IE浏览器内存泄露问题
    IE内存泄露与无法回收研究小结
  • 原文地址:https://www.cnblogs.com/set-cookie/p/8996951.html
Copyright © 2020-2023  润新知