Saturday 25 March 2017

Adapter Classes & Inner Classes - Java Tutorials

Adapter Classes

Java provides a special feature, called an adapter class, that can simplify the creation of event handlers in certain situations. An adapter class provides an empty implementation of all methods in an event listener interface. Adapter classes are useful when you want to receive and process only some of the events that are handled by a particular event listener interface. You can define a new class to act as an event listener by extending one of the adapter classes and implementing only those events in which you are interested.

For example,  the MouseMotionAdapter class has two methods, mouseDragged( ) and  mouseMoved ( ). The signatures of these empty methods are exactly as defined in the MouseMotionListener interface. If you were interested in only mouse drag events, then you could simply extend MouseMotionAdapter and implement mouseDragged( ). The empty implementation of mouseMoved ( ) would handle the mouse motion events for you. Lists the commonly used adapter classes in java.awt.event and notes the interface that each implements.

The following example demonstrates an adapter. It displays a message in the status bar of an applet viewer or browser when the mouse is clicked or dragged. However, all other mouse events are silently ignored. The program has three classes. AdapterDemo extends Applet. Its init( ) method creates an instance of MyMouseAdapter and registers that object to receive notifications of mouse events. It also creates an instance of MyMouseMotionAdapter and registers that object to receive notifications of mouse motion events. Both of the constructors take a reference to the applet as an argument.

MyMouseAdapter implements the mouseClicked( ) method. The other mouse events are silently ignored by code inherited from the MouseAdapter class. MyMouseMotionAdapter implements the mouseDragged( ) method. The other mouse motion event is silently ignored by code inherited from the MouseMotionAdapter class.


Commonly Used Listener Interfaces Implemented by Adapter Classes

ComponentAdapter  --  ComponentListener

ContainerAdapter  --  ContainerListener

FocusAdapter  --  FocusListener

KeyAdapter  --  KeyListener

MouseAdapter  --  MouseListener

MouseMotionAdapter  --  MouseMotionListener

WindowAdapter  --  WindowListener


Note that both of our event listener classes save a reference to the applet. This information is provided as an argument to their constructors and is used later to invoke the showStatus( ) method.

  // Demonstrate an adapter.
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
  /*
    <applet code="AdapterDemo" width=300 height=100>
    </applet>
  */

  public class AdapterDemo extends Applet {
    public void init() {
       addMouseListener(new MyMouseAdapter(this));
       addMouseMotionListener(new MyMouseMotionAdapter(this));
    }
  }

  class MyMouseAdapter extends MouseAdapter {

    AdapterDemo adapterDemo;
    public MyMouseAdapter(AdapterDemo adapterDemo) {
      this.adapterDemo = adapterDemo;
    }

    // Handle mouse clicked.
    public void mouseClicked(MouseEvent me) {
      adapterDemo.showStatus("Mouse clicked");
    }
  }
  
  class MyMouseMotionAdapter extends MouseMotionAdapter {
    AdapterDemo adapterDemo;
    public MyMouseMotionAdapter(AdapterDemo adapterDemo) {
      this.adapterDemo = adapterDemo;
    }

    // Handle mouse dragged.
    public void mouseDragged(MouseEvent me) {
      adapterDemo.showStatus("Mouse dragged");
    }
  }

As you can see by looking at the program, not having to implement all of the methods defined by the MouseMotionListener and MouseListener interfaces saves you a considerable amount of effort and prevents your code from becoming cluttered with empty methods. As an exercise, you might want to try rewriting one of the keyboard input examples shown earlier so that it uses a KeyAdapter.




Inner Classes

In Chapter 7, the basics of inner classes were explained. Here you will see why they are important. Recall that an inner class is a class defined within other class, or even within an expression. This section illustrates how inner classes can be used to simplify the code when using event adapter classes.

To understand the benefit provided by inner classes, consider the applet shown in the following listing. It does not use an inner class. Its goal is to display the string “Mouse Pressed” in the status bar of the applet viewer or browser when the mouse is pressed. There are two top-level classes in this program. MousePressedDemo extends Applet, and MyMouseAdapter extends MouseAdapter. The init( ) method of MousePressedDemo instantiates MyMouseAdapter and provides this object as an argument to the addMouseListener( ) method.

Notice that a reference to the applet is supplied as an argument to the MyMouseAdapter constructor. This reference is stored in an instance variable for later use by the mousePressed( ) method. When the mouse is pressed, it invokes the showStatus( ) method of the applet through the stored applet reference. In other words, showStatus( ) is invoked relative to the applet reference stored by MyMouseAdapter.

  // This applet does NOT use an inner class.
  import java.applet.*;
  import java.awt.event.*;
  /*
    <applet code="MousePressedDemo" width=200 height=100>
    </applet>
  */

  public class MousePressedDemo extends Applet {
    public void init() {
      addMouseListener(new MyMouseAdapter(this));
    }
  }

  class MyMouseAdapter extends MouseAdapter {
    MousePressedDemo mousePressedDemo;
    public MyMouseAdapter(MousePressedDemo mousePressedDemo) {
      this.mousePressedDemo = mousePressedDemo;
    }

    public void mousePressed(MouseEvent me) {
      mousePressedDemo.showStatus("Mouse Pressed.");
    }
  }

The following listing shows how the preceding program can be improved by using an inner class. Here, InnerClassDemo is a top-level class that extends Applet. MyMouseAdapter is an inner class that extends MouseAdapter. Because MyMouseAdapter is defined within the scope of InnerClassDemo, it has access to all of the variables and methods within the scope of that class. Therefore, the mousePressed( ) method can call the showStatus( ) method directly. It no longer needs to do this via a stored reference to the applet. Thus, it is no longer necessary to pass MyMouseAdapter( ) a reference to the invoking object.

  // Inner class demo.
  import java.applet.*;
  import java.awt.event.*;
  /*
    <applet code="InnerClassDemo" width=200 height=100>
    </applet>
  */

  public class InnerClassDemo extends Applet {
    public void init() {
      addMouseListener(new MyMouseAdapter());
    }
    class MyMouseAdapter extends MouseAdapter {
      public void mousePressed(MouseEvent me) {
        showStatus("Mouse Pressed");
      }
    }
  }


Anonymous Inner Classes

An anonymous inner class is one that is not assigned a name. This section illustrates how an anonymous inner class can facilitate the writing of event handlers. Consider the applet shown in the following listing. As before, its goal is to display the string “Mouse Pressed” in the status bar of the applet viewer or browser when the mouse is pressed.

  // Anonymous inner class demo.
  import java.applet.*;
  import java.awt.event.*;
  /*
    <applet code="AnonymousInnerClassDemo" width=200 height=100>
    </applet>
  */

  public class AnonymousInnerClassDemo extends Applet {
    public void init() {
      addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent me) {
          showStatus("Mouse Pressed");
        }
      });
    }
  }

There is one top-level class in this program: AnonymousInnerClassDemo. The init( ) method calls the addMouseListener( ) method. Its argument is an expression that defines and instantiates an anonymous inner class. Let’s analyze this expression carefully.

The syntax new MouseAdapter( ) { ... } indicates to the compiler that the code between the braces defines an anonymous inner class. Furthermore, that class extends MouseAdapter. This new class is not named, but it is automatically instantiated when this expression is executed.

Because this anonymous inner class is defined within the scope of AnonymousInnerClassDemo, it has access to all of the variables and methods within the scope of that class. Therefore, it can call the showStatus( ) method directly. As just illustrated, both named and anonymous inner classes solve some annoying problems in a simple yet effective way. They also allow you to create more efficient code.

No comments:

Post a Comment