next up previous contents
Next: Bean's PropertyとPropertyChangeEvent Up: JDK1.1のイベント・モデル Previous: イベントの送り出しとメソッドの呼び出し

java.awt.AWTEventMulticaster クラス

java.awt.AWTEventMulticasterクラスは、AWT component上で発生するイベ ントの処理 (登録メソッドの定義、Listenerの登録、イベントの送り出し 等)を 一手に下請けしている新しいイベント・モデルの心臓部といってよい クラスです。

Buttonクラスでの利用例

たとえば、Buttonクラスでは、JDK1.1のcomponentクラスが持 っている通常の イベント処理に加えて、ActionEventへの対応が、もちろん可 能となっているのですが、 java.awt.Buttonクラスのソースから、イベント 処理に関係する部分を抜き出してみました。 この例は、componentを拡大して 新しいクラスを作成する時に、イベント処理のために AWTEventMulticaster クラスを利用する場合のいいサンプルになっています。 このサンプルを中心 に、AWTEventMulticasterクラスの働きを見てみることにしましょう。

==========================================================================
public class Button extends Component {

    String label;
    String actionCommand;

    transient ActionListener actionListener = null;
    .....................
    .....................       
    public void addActionListener(ActionListener l) {
        actionListener = AWTEventMulticaster.add(actionListener, l);
        newEventsOnly = true;   
    }
    protected void processEvent(AWTEvent e) {
        if (e instanceof ActionEvent) {
            processActionEvent((ActionEvent)e);     
            return;
        }
        super.processEvent(e);
    }
    protected void processActionEvent(ActionEvent e) {
        if (actionListener != null) {
            actionListener.actionPerformed(e);
        }
    }
    .....................
    ..................... 
}
===========================================================================

ここでは、Listenerの記憶場所に、VectorもHashtableも使われていません。 どうやらactionListenerという変数が、その記憶場所のようなのですが、そ の 型は、Classではなく ActionListenerというInterfaceになっています。 また、processActionEventというメソッドで、Listenerへのイベントの送り 出しが 行われているのですが、その仕掛けは、このコードを見ているだけで は分かりません。

変数のInterface宣言の意味

今度は、 Buttonクラスの ActionEventに関係する、AWTEventMulticaster クラスのソースを 抜き出して見ました。

ここで重要なのは、このクラスのフィールドを構成する protected EventListener a, b; という 宣言の意味です。ここでのEventListenerは、 java.util.EventListenerのことですが、問題は この EventListenerが、 ClassではなくInterfaceであるということです。 Javaでは、変数が Interfaceと宣言されることがあるのですが、これは、この変数が表わすオブ ジェクトが このInterfaceをimplementsしたクラスのインスタンスであるこ とを表わします。この例で言えば、 オブジェクトa,bは、いずれも EventListener Interfaceをimplementsしたクラスのインスタンスで なけれ ばならないということです。JDK1.1の新しいイベント・モデルでは、全ての Listenerは、 java.util.Listener を継承・拡大したものですから、 Listenerを implementsしたクラスの オブジェクト listener は、全て EventListener listener ; という宣言が可能であることが 分かります。

それだけではありません。AWTEventMulticaster クラスの定義を見ると、そ のクラスが、 ComponentListener, ContainerListener, FocusListener, KeyListener, MouseListener, MouseMotionListener, WindowListener, ActionListener, ItemListener, AdjustmentListener, TextListener と いった Listener Interface達をimplementsしていることが分かります。こ れらは、 いうまでもなくListenerですので、AWTEventMulticaster クラス 自体のインスタンスをも、EventListenerで 型付けすることが可能になりま す。

=======================================================================================
public class AWTEventMulticaster implements 
    ComponentListener, ContainerListener, FocusListener, KeyListener,
    MouseListener, MouseMotionListener, WindowListener,
    ActionListener, ItemListener, AdjustmentListener,
    TextListener {

    protected EventListener a, b;
    protected AWTEventMulticaster(EventListener a, EventListener b) {
        this.a = a; this.b = b;
    }
    .....................
    ..................... 
    public void actionPerformed(ActionEvent e) {
        ((ActionListener)a).actionPerformed(e);
        ((ActionListener)b).actionPerformed(e);
    }
    .....................
    ..................... 
    public static ActionListener add(ActionListener a, ActionListener b) {
        return (ActionListener)addInternal(a, b);
    }
    .....................
    ..................... 
    protected static EventListener addInternal(EventListener a, EventListener b) {
        if (a == null)  return b;
        if (b == null)  return a;
        return new AWTEventMulticaster(a, b);
    }
    protected static EventListener removeInternal(EventListener l, EventListener oldl) {
        if (l == oldl || l == null) {
            return null;
        } else if (l instanceof AWTEventMulticaster) {
            return ((AWTEventMulticaster)l).remove(oldl);
        } else {
            return l;           // it's not here
        }
    }
    .....................
    .....................  
}

=======================================================================================

オブジェクトの表記(dot notation)

AWTEventMulticasterクラスには、protected EventListener a, b; で 宣 言された a,bという二つの フィールドがあります。今、コンストラクタ new AWTEventMulticaster(a,b)で生成される、このクラスの オブジェクトを、 (a . b) で表わすことにしましょう。こうした表記を、Dot Notationといい ます。

問題は、先にも述べたように、こうして生成された、AWTEventMulticaster クラスのオブジェクトを、 再度、EventListenerで型付けすることが可能だ ということです。ですから、x=(a . b)とすれば、 EventListener x; です ので、あるEventListener c に対して、new AWTEventMulticaster(x,c)を 考えることが出来ます。こうして生成されるオブジェクトは、(x . c)であ り、((a . b) . c)と 表わすことが出来ます。

改めて、こうして生成されたオブジェクトをyとすれば、 EventListener y; ですので、あるEventListener d に対して、new AWTEventMulticaster(y,d)を 考えることが出来ます。こうして生成されるオ ブジェクトは、(y . d)であり、 (((a . b) . c) . d)と表わすことが出来 ます。こうした操作は、何回でも繰り返すことが 出来ます。

   x1 = new AWTEventMulticaster(a ,b);     x1=(a . b)
   x2 = new AWTEventMulticaster(x1,c);     x2=((a . b) . c)
   x3 = new AWTEventMulticaster(x2,d);     x3=(((a . b) . c) . d)
  x4 = new AWTEventMulticaster(x3,e);     x4=((((a . b) . c) . d) . e)
   x5 = new AWTEventMulticaster(x4,e);     x5=(((((a . b) . c) . d) . e) . f)
    .............
    .............

ButtonクラスでのAddActionListener

Buttonクラスでの AddActionListenerメソッドがどのような働きをするか見 てみましょう。

    public void addActionListener(ActionListener l) {
        actionListener = AWTEventMulticaster.add(actionListener, l);
        newEventsOnly = true;   
    }

ですから、これは、AWTEventMulticasterクラス内のaddメソッドの呼び出し を行うことが 分かります。このクラスのソースを見てもらえば分かります が、引数のListenerの型に応じて、 沢山のaddメソッドが用意されています が、この場合には、ActionListenerを引数とするaddメソッド が呼ばれるこ とになります。

実は、これらのListenerの型に応じて存在する沢山のaddメソッドは、内部的 には、まったく同じで、 addInternalというメソッドを呼び出して、その結果 を引数と同じListenerの型にキャストする だけのものです。

addInternal(a, b)メソッドは、先の表記法を用いれば、(a . b)を返しま す。 ただし、(null . b) = b であり、(a . null) = a という条件が含ま れています。

    public static ActionListener add(ActionListener a, ActionListener b) {
        return (ActionListener)addInternal(a, b);
    }
    protected static EventListener addInternal(EventListener a, EventListener b) {
        if (a == null)  return b;
        if (b == null)  return a;
        return new AWTEventMulticaster(a, b);
    }

ですから、あるButtonクラスのインスタンス上で、 addListener(a),addListener(b),addListener(c)... を繰り返せば、この オブジェクト上のactionListener変数には、次のような値が入ることになり ます。

                              actionListener = null;
    addListener(a);           actionListener = (null . a) = a 
    addListener(b);           actionListener = (a . b) 
    addListener(c);           actionListener = ((a . b) . c)
    addListener(d);           actionListener = (((a . b) . c) . d)
    ..........

ButtonクラスでのActionイベント処理

Buttonクラスのイベント処理は、次のようなメソッドが関わりますが、 AWTEventの場合には、 基本的には、actionListenerオブジェクト上での actionPerformedメソッドの呼び出しに 帰着します。

 =======================================================================================
    protected void processEvent(AWTEvent e) {
        if (e instanceof ActionEvent) {
            processActionEvent((ActionEvent)e);     
            return;
        }
        super.processEvent(e);
    }
    protected void processActionEvent(ActionEvent e) {
        if (actionListener != null) {
            actionListener.actionPerformed(e);
        }
    }
 =======================================================================================

今、actionListener = (((a . b) . c) . d)のとき、 actionListener.actionPerformed(e); がどのようになるのかを見てみまし ょう。

 =======================================================================================
    public void actionPerformed(ActionEvent e) {
        ((ActionListener)a).actionPerformed(e);
        ((ActionListener)b).actionPerformed(e);
    }  
              だから
   actionListener.actionPerformed(e) =
   (((a . b) . c) . d).actionPerformed(e) = {
       ((a . b) . c).actionPerformed(e);
       d.actionPerformed(e);          
   } = {
       (a . b).actionPerformed(e);
       c.actionPerformed(e);
       d.actionPerformed(e);          
   }= {
       a.actionPerformed(e);
       b.actionPerformed(e);
       c.actionPerformed(e);
       d.actionPerformed(e);          
   }
 =======================================================================================

こうして、recursiveにactionPerformedが呼ばれて、結局、登録された全て のListener上で、 actionPerformedが呼ばれることになります。

ActionEvent以外のイベント処理

ActionListenerではactionPerformedメソッドが呼ばれるように、Listener の種類に応じて 呼び出されるべきメソッドは異なります。ActionEvent以外の イベント処理も基本的には、 AWTEventMulticasterクラスを用いて行われま す。以下に、AWTEventMulticasterのソースがら、 いくつかの例を挙げてみ たいと思います。沢山の種類があるように見えますが、基本的には、 リスト 構造をrecursiveに処理するという点で、全く同じ構造をしていることに注目 して 下さい。

=======================================================================================
    public void focusGained(FocusEvent e) {
        ((FocusListener)a).focusGained(e);
        ((FocusListener)b).focusGained(e);
    }
    public void keyPressed(KeyEvent e) {
        ((KeyListener)a).keyPressed(e);
        ((KeyListener)b).keyPressed(e);
    }
    public void mouseReleased(MouseEvent e) {
        ((MouseListener)a).mouseReleased(e);
        ((MouseListener)b).mouseReleased(e);
    }
    public void windowClosed(WindowEvent e) {
        ((WindowListener)a).windowClosed(e);
        ((WindowListener)b).windowClosed(e);
    }
    public void itemStateChanged(ItemEvent e) {
        ((ItemListener)a).itemStateChanged(e);
        ((ItemListener)b).itemStateChanged(e);
    }
    public void textValueChanged(TextEvent e) {
        ((TextListener)a).textValueChanged(e);
        ((TextListener)b).textValueChanged(e);
    }
=======================================================================================

ButtonクラスでのremoveActionListener

ButtonクラスのremoveActionListenerは、 AWTEventMulticaster.remove(actionListener, l) で定義されています。 AWTEventMulticasterクラスの次のソースから、emoveActionListenerメソッ ドの 働きを考えて見てください。今までのよりは、ちょっとわかりにくいか もしれませんが、 ちょうどいい練習になります。

=======================================================================================
    public static ActionListener remove(ActionListener l, ActionListener oldl) {        return (ActionListener) removeInternal(l, oldl);
    }
    protected static EventListener removeInternal(EventListener l, EventListener oldl) {
        if (l == oldl || l == null) {
            return null;
        } else if (l instanceof AWTEventMulticaster) {
            return ((AWTEventMulticaster)l).remove(oldl);
        } else {
            return l;           // it's not here
        }
    }
=======================================================================================


maruyama@wakhok.ac.jp