Java基础12-深入理解Java中回调机制(二 )

简介: Java基础12-深入理解Java中回调机制(二 )

Java基础12-深入理解Java中回调机制(一):https://developer.aliyun.com/article/1535683

实例二:由浅入深

前几天公司面试有问道java回调的问题,因为这方面也没有太多研究,所以回答的含糊不清,这回特意来补习一下。看了看网上的回调解释和例子,都那么的绕口,得看半天才能绕回来,其实吧,回调是个很简单的机制。在这里我用简单的语言先来解释一下:假设有两个类,分别是A和B,在A中有一个方法a(),B中有一个方法b();在A里面调用B中的方法b(),而方法b()中调用了方法a(),这样子就同时实现了b()和a()两个方法的功能。

疑惑:为啥这么麻烦,我直接在类A中的B.b()方法下调用a()方法就行了呗。解答:回调更像是一个约定,就是如果我调用了b()方法,那么就必须要回调,而不需要显示调用一、Java的回调-浅我们用例子来解释:小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。一起去吃饭这个事件就是方法a(),小李去洗漱就是方法b()。

public class XiaoMing { 
   //小明和小李一起吃饭
   public void eatFood() {
      XiaoLi xl = new XiaoLi();
      //A调用B的方法
      xl.washFace();
   }
 
   public void eat() {
      System.out.print("小明和小李一起去吃大龙虾");
   }
}
那么怎么让小李洗漱完后在通知小明一起去吃饭呢

public class XiaoMing { 
   //小明和小李一起吃饭
   public void eatFood() {
      XiaoLi xl = new XiaoLi();
      //A调用B的方法
      xl.washFace();
      eat();
   }
 
   public void eat() {
      System.out.print("小明和小李一起去吃大龙虾");
   }
}复制代码

不过上面已经说过了这个不是回调函数,所以不能这样子,正确的方式如下

public class XiaoLi{//小李
   public void washFace() {
    System.out.print("小李要洗漱");
    XiaoMing xm = new XiaoMing();
        //B调用A的方法
    xm.eat();//洗漱完后,一起去吃饭
   }
}复制代码

这样子就可以实现washFace()同时也能实现eat()。小李洗漱完后,再通知小明一起去吃饭,这就是回调。

二、Java的回调-中可是细心的伙伴可能会发现,小李的代码完全写死了,这样子的场合可能适用和小明一起去吃饭,可是假如小李洗漱完不吃饭了,想和小王上网去,这样子就不适用了。其实上面是伪代码,仅仅是帮助大家理解的,真正情况下是需要利用接口来设置回调的。现在我们继续用小明和小李去吃饭的例子来讲讲接口是如何使用的。

小明和小李相约一起去吃早饭,但是小李起的有点晚要先洗漱,等小李洗漱完成后,通知小明再一起去吃饭。小明就是类A,小李就是类B。不同的是我们新建一个吃饭的接口EatRice,接口中有个抽象方法eat()。在小明中调用这个接口,并实现eat();小李声明这个接口对象,并且调用这个接口的抽象方法。这里可能有点绕口,不过没关系,看看例子就很清楚了。

EatRice接口:

public interface EatRice {
   public void eat(String food);
}
小明:

public class XiaoMing implements EatRice{//小明
    
   //小明和小李一起吃饭
   public void eatFood() {
    XiaoLi xl = new XiaoLi();
    //A调用B的方法
    xl.washFace("大龙虾", this);//this指的是小明这个类实现的EatRice接口
   }
 
   @Override
   public void eat(String food) {
    // TODO Auto-generated method stub
    System.out.println("小明和小李一起去吃" + food);
   }
}
小李:

public class XiaoLi{//小李
   public void washFace(String food,EatRice er) {
    System.out.println("小李要洗漱");
        //B调用了A的方法
    er.eat(food);
   }
}
测试Demo:

public class demo {
   public static void main(String args[]) {
    XiaoMing xm = new XiaoMing();
    xm.eatFood();
   }
}复制代码

测试结果:

这样子就通过接口的形式实现了软编码。通过接口的形式我可以实现小李洗漱完后,和小王一起去上网。代码如下

public class XiaoWang implements EatRice{//小王
    
   //小王和小李一起去上网
   public void eatFood() {
    XiaoLi xl = new XiaoLi();
    //A调用B的方法
    xl.washFace("轻舞飞扬上网", this);
   }
 
   @Override
   public void eat(String bar) {
    // TODO Auto-generated method stub
    System.out.println("小王和小李一起去" + bar);
   }
}复制代码

实例三:Tom做题

数学老师让Tom做一道题,并且Tom做题期间数学老师不用盯着Tom,而是在玩手机,等Tom把题目做完后再把答案告诉老师。

1 数学老师需要Tom的一个引用,然后才能将题目发给Tom。

2 数学老师需要提供一个方法以便Tom做完题目以后能够将答案告诉他。

3 Tom需要数学老师的一个引用,以便Tom把答案给这位老师,而不是隔壁的体育老师。

回调接口,可以理解为老师接口

    //回调指的是A调用B来做一件事,B做完以后将结果告诉给A,这期间A可以做别的事情。
    //这个接口中有一个方法,意为B做完题目后告诉A时使用的方法。
    //所以我们必须提供这个接口以便让B来回调。
    //回调接口,
    public interface CallBack {
        void tellAnswer(int res);
    }复制代码

数学老师类

    //老师类实例化回调接口,即学生写完题目之后通过老师的提供的方法进行回调。
    //那么学生如何调用到老师的方法呢,只要在学生类的方法中传入老师的引用即可。
    //而老师需要指定学生答题,所以也要传入学生的实例。
public class Teacher implements CallBack{
    private Student student;

    Teacher(Student student) {
        this.student = student;
    }

    void askProblem (Student student, Teacher teacher) {
        //main方法是主线程运行,为了实现异步回调,这里开启一个线程来操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                student.resolveProblem(teacher);
            }
        }).start();
        //老师让学生做题以后,等待学生回答的这段时间,可以做别的事,比如玩手机.\
        //而不需要同步等待,这就是回调的好处。
        //当然你可以说开启一个线程让学生做题就行了,但是这样无法让学生通知老师。
        //需要另外的机制去实现通知过程。
        // 当然,多线程中的future和callable也可以实现数据获取的功能。
        for (int i = 1;i < 4;i ++) {
            System.out.println("等学生回答问题的时候老师玩了 " + i + "秒的手机");
        }
    }

    @Override
    public void tellAnswer(int res) {
        System.out.println("the answer is " + res);
    }
}复制代码

学生接口

    //学生的接口,解决问题的方法中要传入老师的引用,否则无法完成对具体实例的回调。
    //写为接口的好处就是,很多个学生都可以实现这个接口,并且老师在提问题时可以通过
    //传入List<Student>来聚合学生,十分方便。
public interface Student {
    void resolveProblem (Teacher teacher);
}复制代码

学生Tom

public class Tom implements Student{

    @Override
    public void resolveProblem(Teacher teacher) {
        try {
            //学生思考了3秒后得到了答案,通过老师提供的回调方法告诉老师。
            Thread.sleep(3000);
            System.out.println("work out");
            teacher.tellAnswer(111);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }复制代码

测试类

public class Test {
    public static void main(String[] args) {
        //测试
        Student tom = new Tom();
        Teacher lee = new Teacher(tom);
        lee.askProblem(tom, lee);
        //结果
//        等学生回答问题的时候老师玩了 1秒的手机
//        等学生回答问题的时候老师玩了 2秒的手机
//        等学生回答问题的时候老师玩了 3秒的手机
//        work out
//        the answer is 111
    }
}
目录
相关文章
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
51 2
|
4天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
2月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
377 37
|
28天前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
17 1
|
1月前
|
Oracle Java 关系型数据库
|
2月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
2月前
|
缓存 安全 Java
【Java面试题汇总】Java基础篇——基础、修饰符和关键字(2023版)
Java的特点和优点,、Java 8的新特性、面向对象、基本数据类型和引用类型、自动拆装箱与自动装箱、==与equals()的区别、为什么重写equals()就要重写hashcode()、抽象类和接口的区别、重载和重写的区别、四种引用方式、wt()和sleep()的区别、java方法是值传递还是引用传递?访问修饰符、static、final、this和super、volatile的用法及原理
【Java面试题汇总】Java基础篇——基础、修饰符和关键字(2023版)
|
3月前
|
存储 安全 Java
java基础Java的Deque之Deque、BlockingDeque、LinkedBlockingDeque、ArrayDeque
在实际编程中,合理利用Java的Deque和它的具体实现,可以在不同的应用场景中发挥高效和线程安全的队列管理功能。通过了解和比较Deque的不同实现,可以根据应用需求做出适当的技术选型,以支持高效且健壮的应用架构。
21 0
|
3月前
|
Java
【Java基础面试四十九】、 说一说Java的四种引用方式
这篇文章介绍了Java中的四种引用方式:强引用、软引用、弱引用和虚引用,它们在垃圾回收时的不同行为及其适用场景。
|
3月前
|
XML Java 数据库连接
【Java基础面试四十八】、 Java反射在实际项目中有哪些应用场景?
这篇文章探讨了Java反射机制在实际项目中的应用场景,包括JDBC数据库驱动加载、框架注解/XML配置实例化,以及面向切面编程(AOP)的代理类创建等。
下一篇
无影云桌面