【问题标题】:Understanding callbacks in Java理解 Java 中的回调
【发布时间】:2013-07-19 11:43:01
【问题描述】:

我一直在努力思考回调,并且一直在努力掌握这个概念。下面的代码是我找到的一个例子here

从头到尾我理解流程是这样的:

  • CallMe 被实例化,从而调用了该类的构造函数
  • 变量en 被设置,随后实例化EventNotifier 类并调用它的构造函数,该构造函数被传递给对象CallMe 的引用
  • 变量ie被设置为对象CallMe,该对象被传递到构造函数中
  • 变量somethinghappened 设置为false(我假设将使用一些条件语句来确定是否设置其他值)
  • 嗯……完成了吗?

我不明白这段代码。 doWork 是如何被调用的?这如何表示一个事件?为什么不简单地从callme 的构造函数调用interestingevent .... 就此而言,为什么不直接调用dowork 来代替任何会改变somethinghappened 值的东西?

尽我所能,我似乎无法理解这个想法。我知道回调主要用于表示事件已发生,例如鼠标或按钮单击,但它如何在事件发生与被调用方法之间建立联系?不应该有一个循环来检查更改,从而触发事件吗?

有人可以提供一个(不过分简化的)java 回调的解释,并帮助澄清这样的事情有什么用处吗?

public interface InterestingEvent
{
    public void interestingEvent ();
}

public class EventNotifier
{
    private InterestingEvent ie;
    private boolean somethingHappened; 
    public EventNotifier (InterestingEvent event)
    {
        ie = event; 
        somethingHappened = false;
    } 

    public void doWork ()
    {
        if (somethingHappened)
        {
            ie.interestingEvent ();
        }
    } 
}

public class CallMe implements InterestingEvent
{
    private EventNotifier en; 
    public CallMe ()
    {
        en = new EventNotifier (this);
    } 

    public void interestingEvent ()
    {
        // Wow!  Something really interesting must have occurred!
        // Do something...
    } 
}

编辑:请查看已批准答案中的 cmets... ---this--- 链接对我很有帮助 =)

【问题讨论】:

    标签: java callback listener


    【解决方案1】:

    没有主方法或静态块。您发布的代码实际上没有运行任何内容;因此,doWork() 永远不会被调用。看了文章,看了下代码,貌似不全,也可能是因为作者觉得不需要解释,所以遗漏了一些代码。

    这里是要点:

    我们有一个interface InterestingEvent,一个class EventNotifier,还有另一个类CallMe,即implements InterestingEvent

    EventNotifier 在其构造函数中采用InterestingEvent,并将somethingHappened 设置为false

    CallMe 的构造函数通过向 EventNotifier 构造函数传递对 CallMe 对象本身的引用来初始化其 EventNotifier 实例成员。

    以下内容不在代码中,但如果我们检测到某些特定动作发生,我们设置somethingHappened = true。所以在那之后,如果doWork() 被调用为EventNotifierinterestingEvent() 将在EventNotifierInterestingEvent ie 上被调用。我们可以这样做,因为CallMe implements InterestingEvent

    注意:这篇文章是 1996 年的,从那以后发生了很大变化。您提到了如何检测鼠标单击事件,但这是不同的。我认为,这篇文章的重点是展示如何将对象与接口和布尔值结合使用,以查看是否发生了某些事情。

    要实际检测鼠标点击,请查看tutorial。这是Writing Event Listeners 的另一个教程。最后,既然您在评论中询问了线程,这是一本很棒的书:Java Concurrency in Practice

    【讨论】:

    • 那么我们将如何检测事件呢?我们会使用带有循环的线程来检测发生某事的信号吗?此外,如果您可以只调用 interestingevent 方法而不是设置布尔值,为什么要这样做?
    • 我不认为这是一个很好的教程或解释,除了说明界面的一些功能......我发布了另一个链接。 Swing 和 AWT 为您提供Listener classes——您不想重新创建轮子。您可以查看特定类的源代码以了解其实际工作原理,但是是的,侦听器将在不同的线程中等待某个特定信号。
    • 那么回调中除了检测外部输入之外没有其他意义吗?据我所知,最大的用途是在不同线程上运行的对象之间传递信息,我是否正确?
    • also -- here -- 是我不久前发布的一个问题,这是回调的例子吗?
    • 如果你问线程之间的通信是否有用,那么是的,它是......这个教程具有高度的误导性/信息量不足而且很古老——不要再关注它了.回调是:作为参数传递给其他代码的一段可执行代码,预期在某个方便的时间回调(执行)该参数。这是Callback functions in Java 的链接。 PS:添加了一些链接。
    【解决方案2】:

    我通常使用回调的方式是使用 PropertyChangeListeners/PropertyChangeSupport 类。关于这些类可能有很多不同的解释,您可能会觉得有帮助。

    不管怎样,直奔你的问题。

    首先,您需要了解您拥有的两个类通常在不同的线程上运行。回调的作用是让您获得异步通知,说明另一个线程发生了某些事情。这允许被通知的线程在重新获得控制权时发挥其作用。例如,您有一条正在接收数据的串行线路。 InterestingEvent 将类似于 10 个字符已到达此行。现在,不再只有一个 EventNotifier,而是为每个进入的串行线路提供一个。CallMe 实例将运行做某事,定期检查是否调用了interestingEvent。有趣的事件会设置某种标志,以便 CallMe 知道它有新数据要处理。当 CallMe 看到时,它会处理任何有趣的事件,然后返回其正常活动。

    接口的全部意义在于有一个明确定义的方式来访问 CallMe 的实例。如果您对此进行更多开发,您可能会想要管理正在访问您的 CallMe 实例的其他实例。这就是阅读我之前提到的 PropertyChange 内容的真正有用之处。

    【讨论】:

    • 所以我可以接受 -this- 我刚才问的问题使用回调吗?
    • 没有。该代码不会按原样编译。我不知道你想做什么。回调的全部意义在于提供两个线程之间的通信。在标准的 java gui swing 应用程序中,键盘和鼠标事件、鼠标点击、按键等,与主应用程序线程位于不同的线程上。回调是您在两者之间进行通信的方式。
    • 我知道代码无法编译,其想法是通过将“this”传递给对象,您可以访问所述对象中“this”的所有成员。我只是想知道回调是什么以及它们是如何使用的,这样我就可以了解我是否应该使用它们,或者我是否可以通过它们的使用来更好地改变我的代码流。您的信息非常有用,将为我提供大量阅读(哦,快乐)谢谢=)
    猜你喜欢
    • 1970-01-01
    • 2011-05-01
    • 2015-10-14
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    • 2012-11-27
    相关资源
    最近更新 更多