Commentary - Anonymous Inner Class Listeners

This discussion is about how to implement action listeners, but applies equally well to other kinds of listeners.

Basic rroblem - Click a button, call a method

Associating a component with a method to call. The listener problem is to associate a method to be called when a component is manipulated by the user, eg, when a button is clicked. This is easy, altho the verbose Java solution makes it seem a little obscure. This explains how to use anonymous inner classes, a popular solution to the listener problem. See Many listener alternatives for other solutions, some of which may be better.

No "method pointers" in Java. Some languages, like C++, use function pointers for this purpose. This kind of mechanism doesn't exist in Java, which has chosen to build on the basic OOP mechanisms to implement this capability.

Anonymous inner classes are very useful, altho they have a somewhat cryptic syntax.

One use. They are often used when only one reference to class is needed, in which case they are defined at the point the reference is needed. In the example below, an anonymous class is created for the button action listener, in the addActionListener() call.

Inside methods. Unlike other inner classes, they can be created inside of a method, at the point an object reference is needed.

Interface name. Following the new keyword, you can write an interface name, followed by "()". This creates an anonymous class that implements that interface.

No constructor. Note that no constructor is possible (there's no name).

Final method variables/parameters. Like other inner classes, an anonymous inner class method can refer to static class variables in the enclosing class. It can also refer to final variables in the enclosing method, but not to either other local variables in the method or to any of the instance variables in the class.

Requires anonymous inner listeners and final local variables

You'll see in the example below how the JFrame subclass style was transformed into the all-in-main style by making an anonymous inner class listener and changing instance variables to final local variables.

Source code: DogYears entirely in main()

DogYears user interface

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
// File   : gui-tutorial/d1/DogYearsGUI_main.java
// Purpose: Shows a different structure for GUI programs.
// Author : Fred Swartz
// Date   : 2006-04-15

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;  // Needed for ActionListener

///////////////////////////////////////////////////// class DogYearsGUI_main
class DogYearsGUI_main {
    //================================================ constants
    private static final int DOG_YEARS_PER_HUMAN_YEAR = 7; 

    public static void main(String[] args) {  //Note 1
    //======================================= final variables
        final JTextField myHumanYearsTF = new JTextField(3);
        final JTextField myDogYearsTF   = new JTextField(3);

         // 1... Create/initialize components
        JButton convertBtn = new JButton("Convert");
        convertBtn.addActionListener(new ActionListener() {  //Note 2
            public void actionPerformed(ActionEvent e) {
                //... Get the value from the dog years textfield.
                String dyStr = myDogYearsTF.getText();
                int dogYears = Integer.parseInt(dyStr);

                //... Convert it - each dog year is worth 7 human years.
                int humanYears = dogYears * DOG_YEARS_PER_HUMAN_YEAR;

                //... Convert to string and set human yrs textfield
                myHumanYearsTF.setText("" + humanYears); 
            }
        });
        
        
        // 2... Create content panel, set layout
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());

        // 3... Add the components to the content panel.
        content.add(new JLabel("Dog Years"));
        content.add(myDogYearsTF);             // Add input field
        content.add(convertBtn);               // Add button
        content.add(new JLabel("Human Years"));
        content.add(myHumanYearsTF);           // Add output field

        // 4... Create window and display it.
        JFrame window = new JFrame("Dog Year Converter");
        window.setContentPane(content);
        window.pack();
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setVisible(true);
    }
}

Notes

  1. The GUI can be built inside main by using "final" instead of instance variables, and anonymous inner class listeners. But subclassing JFrame is a more common style, .
  2. "Anonymous inner class" listeners are a common way to attach listeners to GUI components. The can be used in the JFrame subclass organization too.