There is a good Oracle tutorial on instantiating and registering Listeners , dealing with events, etc. ( link ). From a conceptual point of view, producers and listeners exist to separate the source of a stimulus and application points interested in dealing with it.
In short:
The hierarchy of components that implement the JButton
functionality (including native components, which is not the case) receives a click notification from the Operating System. There is a lot of work going on in the JVM to know that that click occurred within the limits of JButton
, at a time that it is active and visible and for the user, as well as to determine if JButton
should actually respond for the event within the hierarchy of nested components.
All JComponent
has a EventListenerList containing the classes interested in "listening" for certain types of events. When you call button.addActionListener
, your ActionListener
is registered in this list:
public void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
An event (inherited from java.util.EventObject
, in this case a ActionEvent ) is created containing the relevant information of the stimulus (the origin, type of event, when it occurred, etc, etc, etc). For JButton
this usually occurs or in the setPressed
method in the DefaultButtonModel or in the fireActionPerformed
method of class AbstractButton
(if you use a lazy model , something that does not come back to case):
ActionEvent e = null;
// ...
e = new ActionEvent(AbstractButton.this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
The interesting thing about the current implementation is that AbstractButton
itself registers itself to listen for model events by simply propagating the events generated by the model to the listeners registered with it (see the code of the inner class / a> to understand how this part works).
It is up to the component to execute the payloads
of Listeners
registered. In the case of JButton
this also occurs in the fireActionPerformed
method:
protected void fireActionPerformed(ActionEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
ActionEvent e = null;
// 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) {
// Lazily create the event:
if (e == null) {
String actionCommand = event.getActionCommand();
if(actionCommand == null) {
actionCommand = getActionCommand();
}
e = // Código do item 3
}
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
Finally, at that point the polymorphism comes into play. One of the ActionListener
s registered for JButton
will be an instance of the SimpleGui1
class (which implements the ActionListener
interface and registered with JButton
in step 2). When the actionPerformed
method is called in step 4, the payload you created is invoked by changing the button text.
public void actionPerformed(ActionEvent event) {
button.setText("I've been clicked!");
}
So, to answer your question, the actionPerformed
method runs on line ((ActionListener)listeners[i+1]).actionPerformed(e);
of method fireActionPerformed
of class AbstractButton
.
If you're wondering why none of these "obscure" details about how ActionListener
is invoked are in Oracle's Sun official tutorial, the reason is encapsulation. These are implementation details (which may change). What API users need to know is that payloads should be written within the methods specified by Listeners , and that Listeners components that produce events consumed by Listeners .