简体   繁体   中英

Java, How does the compiler know which constructor to call in this lambda expression

I have a question, I'm learning java with a Book, and as I've copied some code in there (and made some changes) and made some investigations, I noticed something odd..., here is the code

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

}

It's just a code that notifies you if a second passes. (this code compiles and runs smoothly)

as you can see Timer Constructor requires 2 pars (int, ActionListener)

public Timer(int delay, ActionListener listener)

and the ActionListener Interface has one method that is actionPerformed and requires ActionEvent parameter

public void actionPerformed(ActionEvent e);

Now here is my question, when calling this actionPerformed Method in that lambda expression above How does the compiler know which constructor to call to instantiate ActionEvent without feeding him any clues about the parameters, ActionEvent has no "No argument Constructor" and the method getWhen() is not static (obj must be instantiated)

Here are all the constructors of 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)

I really hope I made myself clear!, Thank you

The compiler does not know! ;-)
It is the Timer instance that will create the ActionEvent instance at runtime every delay and the Timer instance will call the ActionListener method actionPerformed with the ActionEvent it created.

You can have a look at one of the implementation here:
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"));
}

If we look at the source code of javax.swing.Timer , we note that all the ActionListeners of the Timer are stored on a javax.swing.event.EventListenerList , called listenerList . They are called in this line(s):

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

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

The regular constructor selection process applies.

The Timer constructor just receives a listener and registers it in its listeners list. When the timer ticks (where listener should be called), the Timer instance creates a new ActionEvent (See Timer.java:245 ) and passes it over to the registered listeners.

So simply saying, the compiler doesn't create it for you. Instead Timer class does.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM