您的位置:首页 > 编程语言 > Java开发

Java的事件监听机制

2017-02-17 23:06 344 查看
关于Java的事件监听机制,我们首先需了解三个概念:

1.事件源(Event Source):即触发事件的对象,比如:Button对象可以修改按钮的状态,也就是说Button对象可以出发按钮按下这个事件。

2.事件状态对象(Event Object):描述事件的对象,对于一类特定的事件,我们需要记录事件发生时的一些状态,比如说事件触发的时间、按钮按下的次数(单击还是双击)、触发事件的对象(即事件源)、对事件的描述等等。我们需要一个专门描述这些状态的事件对象EventObject。

3.事件监听器(Event Listener):当我们打开QQ时,点击登陆按钮,立即显示出了好友列表的界面。即当登陆这个按钮被点击后(即点击事件被触发),程序执行了密码验证登陆QQ拉取好友列表等操作。那么,是哪些对象执行了这些操作呢?这些对象又是如何知道何时执行这些操作的呢?这便提出了事件监听的概念,对于在按钮点击后需要进行操作的那些对象,注册事件监听器(即实现ActionListener接口),并且实现actionPerformed(ActionEvent)方法,在这个方法中是对象在事件触发后具体的操作。JDK中的源码如下:

public interface ActionListener extends EventListener {

    /**

     * Invoked when an action occurs.

     */

    public void actionPerformed(ActionEvent e);

}

那么以上的三种对象是如何关联起来的呢?下面我们以Java的JButton类的实现描述一下三者的关系

在JDK源码中,我们可以发现,JButton继承AbstractButton类:

public class JButton extends AbstractButton implements Accessible

JButton类和AbstractButton类即我们上面提到的事件源

在AbstractButton类中,有一个方法addActionListener(ActionListener) 

public void addActionListener(ActionListener l) {
        listenerList.add(ActionListener.class, l);

    }

listenerList是AbstractButton类的一个成员变量

 protected EventListenerList listenerList = new EventListenerList();

EventListenerList是一个比较简单的类,我们贴出这个类的源码如下:

public class EventListenerList implements Serializable {

    /* A null array to be shared by all empty listener lists*/

    private final static Object[] NULL_ARRAY = new Object[0];

    /* The list of ListenerType - Listener pairs */

    protected transient Object[] listenerList = NULL_ARRAY;


    public Object[] getListenerList() {

        return listenerList;

    }

    /**

     * Return an array of all the listeners of the given type.

     * @return all of the listeners of the specified type.

     * @exception  ClassCastException if the supplied class

     *          is not assignable to EventListener

     *

     * @since 1.3

     */

    public <T extends EventListener> T[] getListeners(Class<T> t) {

        Object[] lList = listenerList;

        int n = getListenerCount(lList, t);

        T[] result = (T[])Array.newInstance(t, n);

        int j = 0;

        for (int i = lList.length-2; i>=0; i-=2) {

            if (lList[i] == t) {

                result[j++] = (T)lList[i+1];

            }

        }

        return result;

    }

    /**

     * Returns the total number of listeners for this listener list.

     */

    public int getListenerCount() {

        return listenerList.length/2;

    }

    /**

     * Returns the total number of listeners of the supplied type

     * for this listener list.

     */

    public int getListenerCount(Class<?> t) {

        Object[] lList = listenerList;

        return getListenerCount(lList, t);

    }

    private int getListenerCount(Object[] list, Class t) {

        int count = 0;

        for (int i = 0; i < list.length; i+=2) {

            if (t == (Class)list[i])

                count++;

        }

        return count;

    }

    /**

     * Adds the listener as a listener of the specified type.

     * @param t the type of the listener to be added

     * @param l the listener to be added

     */

    public synchronized <T extends EventListener> void add(Class<T> t, T l) {

        if (l==null) {

            // In an ideal world, we would do an assertion here

            // to help developers know they are probably doing

            // something wrong

            return;

        }

        if (!t.isInstance(l)) {

            throw new IllegalArgumentException("Listener " + l +

                                         " is not of type " + t);

        }

        if (listenerList == NULL_ARRAY) {

            // if this is the first listener added,

            // initialize the lists

            listenerList = new Object[] { t, l };

        } else {

            // Otherwise copy the array and add the new listener

            int i = listenerList.length;

            Object[] tmp = new Object[i+2];

            System.arraycopy(listenerList, 0, tmp, 0, i);

            tmp[i] = t;

            tmp[i+1] = l;

            listenerList = tmp;

        }

    }

    /**

     * Removes the listener as a listener of the specified type.

     * @param t the type of the listener to be removed

     * @param l the listener to be removed

     */

    public synchronized <T extends EventListener> void remove(Class<T> t, T l) {

        if (l ==null) {

            // In an ideal world, we would do an assertion here

            // to help developers know they are probably doing

            // something wrong

            return;

        }

        if (!t.isInstance(l)) {

            throw new IllegalArgumentException("Listener " + l +

                                         " is not of type " + t);

        }

        // Is l on the list?

        int index = -1;

        for (int i = listenerList.length-2; i>=0; i-=2) {

            if ((listenerList[i]==t) && (listenerList[i+1].equals(l) == true)) {

                index = i;

                break;

            }

        }

        // If so,  remove it

        if (index != -1) {

     
af9f
      Object[] tmp = new Object[listenerList.length-2];

            // Copy the list up to index

            System.arraycopy(listenerList, 0, tmp, 0, index);

            // Copy from two past the index, up to

            // the end of tmp (which is two elements

            // shorter than the old list)

            if (index < tmp.length)

                System.arraycopy(listenerList, index+2, tmp, index,

                                 tmp.length - index);

            // set the listener array to the new array or null

            listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp;

            }

    }

    // Serialization support.

    private void writeObject(ObjectOutputStream s) throws IOException {

        Object[] lList = listenerList;

        s.defaultWriteObject();

        // Save the non-null event listeners:

        for (int i = 0; i < lList.length; i+=2) {

            Class<?> t = (Class)lList[i];

            EventListener l = (EventListener)lList[i+1];

            if ((l!=null) && (l instanceof Serializable)) {

                s.writeObject(t.getName());

                s.writeObject(l);

            }

        }

        s.writeObject(null);

    }

    private void readObject(ObjectInputStream s)

        throws IOException, ClassNotFoundException {

        listenerList = NULL_ARRAY;

        s.defaultReadObject();

        Object listenerTypeOrNull;

        while (null != (listenerTypeOrNull = s.readObject())) {

            ClassLoader cl = Thread.currentThread().getContextClassLoader();

            EventListener l = (EventListener)s.readObject();

            String name = (String) listenerTypeOrNull;

            ReflectUtil.checkPackageAccess(name);

            add((Class<EventListener>)Class.forName(name, true, cl), l);

        }

    }

    /**

     * Returns a string representation of the EventListenerList.

     */

    public String toString() {

        Object[] lList = listenerList;

        String s = "EventListenerList: ";

        s += lList.length/2 + " listeners: ";

        for (int i = 0 ; i <= lList.length-2 ; i+=2) {

            s += " type " + ((Class)lList[i]).getName();

            s += " listener " + lList[i+1];

        }

        return s;

    }

}

分析上面的源码我们可以发现,EventListenerList是一个存储Object对象的类,它的成员变量listenerList
就是一个Object对象数组,这个类主要用于操作这个对象数组,在AbstractButton类的addActionListener方法中,listenerList调用了add方法添加事件监听器。

由上面的分析可以看出,在事件源中添加事件监听器,每个等待事件触发需要进行操作的对象都实现了事件监听器接口,然后事件源对象调用addActionListener方法添加等待操作的事件触发器,一个事件源可以添加多个事件监听器。

当事件触发时,事件源对象会调用存在该对象中的listenerList中的每个监听器的actionPerformed的方法实现监听对象的操作。这便是Java的事件监听机制的部分原理。虽然源码读起来有些难度,但大家在读源码的时候关键是理解其中体现出的设计思想,一定不要仅仅拘泥于代码层面

有些内容限于本人技术水平有限,可能讲的比较啰嗦,如有不足读者可以提出,大家一起讨论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: