Java的事件监听机制

关于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) {
            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的事件监听机制的部分原理。虽然源码读起来有些难度,但大家在读源码的时候关键是理解其中体现出的设计思想,一定不要仅仅拘泥于代码层面


有些内容限于本人技术水平有限,可能讲的比较啰嗦,如有不足读者可以提出,大家一起讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值