目录
1、 函数指针进化论 ........................................................................................................................................................... 1
1.1 C/C++函数指针 .................................................................................................................................................... 1
1.2 Java 反射、多线程和回调 .................................................................................................................................. 2
1.3 C#委托、多线程和回调 ...................................................................................................................................... 4
1.4 参考资源 ............................................................................................................................................................. 10
2、 Java 事件模型 ........................................................................................................................................................... 11
2.1 五种事件处理方式 ............................................................................................................................................. 11
2.2 自定义 Java 事件 ............................................................................................................................................... 16
2.3 Swing 事件调度线程(Event Dispatch Thread, EDT) ................................................................................. 18
2.4 参考资源 ............................................................................................................................................................. 18
3、 .NET(C#)事件模型 ............................................................................................................................................... 19
3.1 C#委托(Delegates in C#) ............................................................................................................................ 19
3.2 C#事件处理(Event Handlers in C#) .......................................................................................................... 19
3.3 发布符合.NET Framework 准则的事件 .......................................................................................................... 22
3.4 应用范例 ............................................................................................................................................................. 24
3.5 参考资源 ............................................................................................................................................................. 29
4、 DOM 和 JavaScript 事件模型 ................................................................................................................................. 30
4.1 异步回调 vs.多线程 ........................................................................................................................................... 30
4.2 DOM 事件流(DOM Event Flow) ................................................................................................................. 31
4.3 绑定事件监听器(Event handler registration) ............................................................................................ 34
4.4 Event Delegation VS. Event Handling ........................................................................................................... 38
4.5 参考资源 ............................................................................................................................................................. 40
5、 Flex 和 ActionScript 3 事件模型 ........................................................................................................................... 41
5.1 概念和术语 ......................................................................................................................................................... 41
5.2 事件对象(Event objects) ............................................................................................................................. 42
5.3 事件流(The event flow) ............................................................................................................................... 42
5.5 禁止默认行为 ..................................................................................................................................................... 43
5.6 创建自定义事件类型 ......................................................................................................................................... 44
5.7 参考资源 ............................................................................................................................................................. 48
函数指针进化论
1
1、 函数指针进化论
函数指针 (function pointer) 是传统 C 语言中少数的动态机制,但是近来许多语言都不再支持函数指针 (包括
Java 和 C#),而改用多态 (polymorphism)、反射 (reflection)、委托 (delegate) 等机制来取代函数指针。
1.1 C/C++函数指针
函数指针(function pointer) 是一种「指向函数的指针」,和一般指向资料的指针不同。凡是研究过许多系统原
代码 (例如:Linux Kernel、Borland OWL) 的人,对于函数指针应该都不陌生,因为多数低阶系统都使用 C 语言
编写,而函数指针是传统 C 语言中少数的动态机制,有许多不可取代的地方,所以这些 C 原代码中到处可见函数
指针。
范例源码
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
//声明Fnc1(),Fnc2(),Twice()
float Fnc1(int);
float Fnc2(int);
double Twice(float (*)(int),int);
//主程序
void main(){
int A=3;
int B=5;
cout<<"Twice(Fnc1,A)的值为:"<<Twice(Fnc1,A)<<endl;
cout<<"Twice(Fnc2,B)的值为:"<<Twice(Fnc2,B)<<endl;
}
float Fnc1(int N){
return float(N*N);
}
float Fnc2(int N){
return float(N*N*N);
}
double Twice(float (*pF)(int),int N){
return 2.0*double(pF(N));
}
运行结果
Twice(Fnc1,A)的值为:18
Twice(Fnc2,B)的值为:250
一旦函数可以被传递、被纪录,这开启了许多可能性,产生许多有趣的应用,特别是下列三者:
1. 多态 (polymorphism)
2. 多线程 (multithreading):将函数指针传进负责建立多线程的 API 中
3. 回调 (call-back):所谓的回调机制就是:「当发生某事件时,自动呼叫某段程序代码」,Charles Petzold 称
此为「Don’t Call Me, I'll Call You」。事件驱动 (event-driven) 的系统经常透过函数指针来实现回调机制
函数指针致命缺点:无法对参数 (parameter) 和返回值 (return value) 的型态进行检查,因为函数已经退化成
指针,指针并不带有这些型态信息。少了型态检查,当参数或返回值不一致时,会造成严重的错误。编译器和虚拟
机 (VM) 并不会帮我们找出函数指针这样的致命错误。所以,许多新的程序语言不支持函数指针,而改用其它方式。
函数指针进化论
2
Java 与 C# 都不支持函数指针。这不会影响对于多态的支持,但是这会不会影响对于多线程 (multithreading)
与回调 (call-back) 机制的支持呢?答案是:不会!因为 Java 可以利用多态或反射 (reflection) 来实现多线程与
回调,而 C#可以利用多态或反射或委托 (delegate) 来实现多线程与回调。
1.2 Java 反射、多线程和回调
A. 反射
范例源码
import java.lang.reflect.*;
public class Invoke {
public static void main(String[] args) {
try {
Class c=Class.forName(args[0]);
Method m=c.getMethod(args[1], new Class[]{});
Object ret=m.invoke(null,null);
System.out.println(args[0]+"."+args[1]+"()="+ret);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("找不到此类别");
} catch (NoSuchMethodException e) {
System.out.println("此方法不存在");
} catch (IllegalAccessException e) {
System.out.println("没有权限调用此方法");
} catch (InvocationTargetException e) {
System.out.println("调用方法时发生下列例外:");
System.out.println(e.getTargetException());
}}}
代码执行
java Invoke java.lang.System currentTimeMillis
运行结果
java.lang.System.currentTimeMillis()=1231215230359
代码说明
我们的第一步就是用名称去寻找指定的 Class。我们用类别名称 (命令列的第一个参数) 去呼叫 forName() 方法,
然后用方法名称 (命令列的第二个参数) 去取得方法。getMethod() 方法有两个参数:第一个是方法名称 (命令列的第二
个参数),第二个是 Class 对象的数组,这个阵例指明了方法的 signature (任何方法都可能会被多载,所以必须指定
signature 来分辨。) 因为我们的简单程序只呼叫没有参数的方法,我们建立一个 Class 对象的匿名空数组。如果我们
想要呼叫有参数的方法,我们可以传递一个类别数组,数组的内容是各个类别的型态,依顺序排列。
一旦我们有了 Method 对象,就呼叫它的 invoke() 方法,这会造成我们的目标方法被调用,并且将结果以 Object
对象传回。如果要对此对象做其它额外的事,你必须将它转型为更精确的型态。
invoke() 方法的第一个参数就是我们想要呼叫目标方法的对象,如果该方法是静态的,就没有对象,所以我们把第
一个参数设为 null,这就是我们范例中的情形。第二个参数是要传给目标方法作为参数的对象数组,它们的型态要符合
呼叫 getMethod() 方法中所指定的型态。因为我们呼叫的方法没有参数,所以我们传递 null 作为 invoke() 的第二个参
数。
以上是 Java 的例子,事实上,.NET 的反射机制也相去不远,不再赘述。反射机制是最动态的机制,比多态的功
能更强大。然而,反射的速度比多态慢许多 (而且多态又比函数指针稍慢),所以若非必要,应该少用反射机制。事实上,
不管是 Java API 或 .NET Framework,都不使用反射机制来实现回调与多线程。
函数指针进化论
3
B. 多线程
Java 使用多态的机制来处理多线程,共有 2 种方式:
第一种方式:
范例源码
/*
* 继承Thread类,唯一缺点是不能再继承其它功能类
*/
public class MyThread extends Thread {
//覆盖run()方法,实现自己的线程任务
public void run() {
System.out.println("++++++++++++");
}
public static void main(String[] args) {
Thread t=new Thread(new MyThread());
t.start();
}
}
第二种方式:
范例源码
/*
* 实现Runnable接口,可以再继承其它功能类
*/
public class MyThread2 implements Runnable {
//实现run()方法,实现自己的线程任务
public void run() {
System.out.println("++++++++++++");
}
public static void main(String[] args) {
Thread t=new Thread(new MyThread2());
t.start();
}
}
C. 回调
Java 使用多态的机制来处理回调,使用 publisher/subscriber (出版者/订阅者) 的方式进行事件处理,详
细内容请参见 3.Java 事件模型