Local and Anonymous Inner Classes

[Page 834 (continued)]

In this next example, ConverterFrame, a local class, is used to create an ActionEvent handler for the application's two buttons (Fig. F.2).

Figure F.2. The use of a local class as an ActionListener adapter.
(This item is displayed on page 835 in the print version)

import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ConverterFrame extends JFrame {    private Converter converter = new Converter();         // Reference to app    private JTextField inField = new JTextField(8);    private JTextField outField = new JTextField(8);    private JButton metersToInch;    private JButton kgsToLbs;    public ConverterFrame() {      metersToInch = createJButton("Meters To Inches");      kgsToLbs = createJButton("Kilos To Pounds");      getContentPane().setLayout( new FlowLayout() );      getContentPane().add(inField);      getContentPane().add(outField);      getContentPane().add(metersToInch);      getContentPane().add(kgsToLbs);    } // ConverterFram()    private JButton createJButton(String s) {   // A method to create a JButton      JButton jbutton = new JButton(s);      class ButtonListener implements ActionListener {      // Local class        public void actionPerformed(ActionEvent e) {          double inValue = double.valueOf(inField.getText()).doubleValue();          JButton button = (JButton) e.getSource();          if (button.getText().equals("Meters To Inches"))            outField.setText(""+ converter.new            Distance().metersToInches(inValue));          else            outField.setText(""+ converter.new Weight().kgsToPounds(inValue));        } // actionPerformed()      } // ButtonListener class      ActionListener listener = new ButtonListener();       // Create a listener      jbutton.addActionListener(listener);     // Register buttons with listener      return jbutton;    } // createJButton()    public static void main(String args[]) {      ConverterFrame frame = new ConverterFrame();      frame.setSize(200,200);      frame.setVisible(true);    } // main() } // ConverterFrame class 

As we have seen, Java's event-handling model uses predefined interfaces, such as the ActionListener interface, to handle events. When a separate class is defined to implement an interface, it is sometimes called an adapter class. Rather than defining adapter classes as top-level classes, it is often more convenient to define them as local or anonymous classes.

The key feature of the ConverterFrame program is the createJButton() method. This method is used instead of the JButton() constructor to create buttons and to create action listeners for the buttons. It takes a single String parameter for the button's label. It begins by instantiating a new JButton, a reference to which is passed back as the method's return value. After creating an instance button, a local inner class named ButtonListener is defined.

The local class merely implements the ActionListener interface by defining the actionPerformed method. Note how actionPerformed() uses the containing class's converter variable to acquire access to the metersToInches() and kgsToPounds() methods, which are inner class methods of the Converter class (Fig. F.1). A local class can use instance variables, such as converter, that are defined in its containing class.

After defining the local inner class, the createJButton() method creates an instance of the class (listener) and registers it as the button's action listener. When a separate object is created to serve as listener in this way, it is called an adapter. It implements a listener interface and thereby serves as adapter between the event and the object that generated the event. Any action events that occur on any buttons created with this method will be handled by this adapter. In other words, for any buttons created by the createJButton() method, a listener object is created and assigned as the button's event listener. The use of local classes makes the code for doing this much more compact and efficient.

[Page 835]

Local classes have some important restrictions. Although an instance of a local class can use fields and methods defined within the class or inherited from its superclasses, it cannot use local variables and parameters defined within its scope unless these are declared final. The reason for this restriction is that final variables receive special handling by the Java compiler. Because the compiler knows that the variable's value won't change, it can replace uses of the variable with their values at compile time.

[Page 836]

Anonymous Inner Classes

An anonymous inner class is just a local class without a name. Instead of using two separate statements to define and instantiate the local class, Java provides syntax that lets you do it in one expression. The following code illustrates how this is done:

private JButton createJButton(String s) {        // A method to create a JButton    JButton jbutton = new JButton(s);    jbutton.addActionListener( new ActionListener() {         // Anonymous class      public void actionPerformed(ActionEvent e) {        double inValue = double.valueOf(inField.getText()).doubleValue();        JButton button = (JButton) e.getSource();        if (button.getLabel().equals("Meters To Inches"))          outField.setText("" + converter.new          Distance().metersToInches(inValue));        else          outField.setText("" + converter.new Weight().kgsToPounds(inValue));        } // actionPerformed()    }); // ActionListener class    return jbutton; } // createJButton() 

Note that the body of the class definition is put right after the new operator. The result is that we still create an instance of the adapter object, but we define it on the fly. If the name following new is a class name, Java will define the anonymous class as a subclass of the named class. If the name following new is an interface, the anonymous class will implement the interface. In this example, the anonymous class is an implementation of the ActionListener interface.

Local and anonymous classes provide an elegant and convenient way to implement adapter classes that are intended to be used once and have relatively short and simple implementations. The choice of local versus anonymous should largely depend on whether you need more than one instance of the class. If so, or if it is important that the class have a name for some other reason (readability), then you should use a local class. Otherwise, use an anonymous class. As in all design decisions of this nature, you should use whichever approach or style makes your code more readable and more understandable.

Java, Java, Java(c) Object-Orienting Problem Solving
Java, Java, Java, Object-Oriented Problem Solving (3rd Edition)
ISBN: 0131474340
EAN: 2147483647
Year: 2005
Pages: 275

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net