【问题标题】:Java, How does the compiler know which constructor to call in this lambda expressionJava,编译器如何知道在这个 lambda 表达式中调用哪个构造函数
【发布时间】:2020-02-16 18:10:13
【问题描述】:

我有一个问题,我正在用一本书学习 java,并且我在其中复制了一些代码(并进行了一些更改)并进行了一些调查,我注意到一些奇怪的东西......,这是代码

public static void main(String[] args)
{
    Timer timer = new Timer(1000, (event) ->
    {
        System.out.println("At the Tone, the time is" + Instant.ofEpochMilli(event.getWhen()));
        Toolkit.getDefaultToolkit().beep();
    });

    timer.start();
    JOptionPane.showMessageDialog(null, "Quit?");
    System.exit(0);

}

这只是一个代码,它会在第二次通过时通知您。 (这段代码编译运行流畅)

如你所见,Timer Constructor 需要 2 个 pars (int, ActionListener)

public Timer(int delay, ActionListener listener)

并且 ActionListener 接口有一个方法是 actionPerformed 并且需要 ActionEvent 参数

public void actionPerformed(ActionEvent e);

现在这是我的问题,在上面的 lambda 表达式中调用此 actionPerformed 方法时 编译器如何知道调用哪个构造函数来实例化 ActionEvent 而没有给他任何关于参数的线索,ActionEvent 没有“无参数构造函数”并且方法 getWhen() 不是静态的(obj 必须实例化)

下面是ActionEvent的所有构造函数:

public ActionEvent(Object source, int id, String command)

public ActionEvent(Object source, int id, String command, int modifiers)

public ActionEvent(Object source, int id, String command, long when,
                   int modifiers)

我真的希望我说清楚了!谢谢

【问题讨论】:

    标签: java


    【解决方案1】:

    编译器不知道! ;-)
    Timer 实例将在运行时创建 ActionEvent 实例,每个 delayTimer 实例将调用 ActionListener 方法 actionPerformed 和它创建的 ActionEvent

    您可以在这里查看其中一个实现:
    http://developer.classpath.org/doc/javax/swing/Timer-source.html

    /**
     * Fire the action event, named "Timer" and having the numeric
     * identifier, equal to the numer of events that have been
     * already fired before.
     */
    void fireActionPerformed()
    {
      fireActionPerformed(new ActionEvent(this, ticks++, "Timer"));
    }
    

    【讨论】:

    • 谢谢你的澄清!但是当 Timer 实例创建 ActionEvent 实例时,它究竟调用了什么构造函数?谢谢
    【解决方案2】:

    如果我们查看javax.swing.Timer 的源代码,我们注意到Timer 的所有ActionListener 都存储在javax.swing.event.EventListenerList 上,称为listenerList。 它们在这一行中被调用:

    fireActionPerformed(new ActionEvent(Timer.this, 0, getActionCommand(),
                                                        System.currentTimeMillis(),
                                                        0));
    

    使用 fireActionPerformed:

    protected void fireActionPerformed(ActionEvent e) {
            // Guaranteed to return a non-null array
            Object[] listeners = listenerList.getListenerList();
    
            // Process the listeners last to first, notifying
            // those that are interested in this event
            for (int i=listeners.length-2; i>=0; i-=2) {
                if (listeners[i]==ActionListener.class) {
                    ((ActionListener)listeners[i+1]).actionPerformed(e);
                }
            }
        }
    

    常规的构造函数选择过程适用。

    【讨论】:

      【解决方案3】:

      Timer 构造函数只接收一个侦听器并将其注册到其侦听器列表中。当计时器计时(应该调用侦听器的位置)时,Timer 实例创建一个新的 ActionEvent(请参阅Timer.java:245)并将其传递给已注册的侦听器。

      简单地说,编译器不会为您创建它。取而代之的是 Timer 类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        • 2010-09-17
        • 2012-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多