java.awt.AWTEventMulticasterクラスは、AWT component上で発生するイベ ントの処理 (登録メソッドの定義、Listenerの登録、イベントの送り出し 等)を 一手に下請けしている新しいイベント・モデルの心臓部といってよい クラスです。
たとえば、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へのイベントの送り 出しが 行われているのですが、その仕掛けは、このコードを見ているだけで は分かりません。
今度は、 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 } } ..................... ..................... } =======================================================================================
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メソッドがどのような働きをするか見 てみましょう。
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クラスのイベント処理は、次のようなメソッドが関わりますが、 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が呼ばれることになります。
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は、 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 } } =======================================================================================