1. Wikipedia: callback(computer science)
2. Implement callback routines in Java By John D. Mitchell, JavaWorld.com, 06/01/96
3. Why is Python more fun than Java? Brian M. Clapper
最近在读Eckel的Thinking in Java,读到Inner Class那一章碰到两个概念不是很清楚,一个是callback,另一个是closures,网上搜了搜,整理如下。
先说callback,粘一段wikipedia的概念。
词条: callback 来自:wikipediaIn computer programming, a callback is executable code that is passed as an argument to other code. It allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.
(下面很多是翻译wikipedia的东西,翻译自然会加入了自己的理解,出错难免。)
为什么需要callback呢?
比如说你想对一个序列中的每个元素进行一次任意的操作,一种方案是遍历这个序列,直接对每个元素进行操作,这是最直接的,缺点是会产生代码冗余,每次遍历都要写重复的代码。另一种方案是写一个泛型的库函数,将序列传递给库函数,在函数的内部遍历操作这个序列,一定程度上消除了代码冗余,问题是使用库函数的应用程序的要求是不可预期的,不可能写出所有满足应用程序要求的库函数。第三种方案当然就是callback,应用程序对序列进行遍历,对每个元素调用callback函数,解决了上述两个问题。
一个用C写的示例:
程序功能:遍历一个整形的数组找出第一个大于5的元素,并给出索引(index)
遍历的方案:
2
3 for (i = 0 ; i < length; i ++ )
4 {
5 if (array[i] > 5 )
6 {
7 break ;
8 }
9 }
10
11 if (i < length)
12 {
13 printf( " Item %d\n " , i);
14 }
15 else
16 {
17 printf( " Not found\n " );
18 }
callback的方案:
2 int traverseWith( int array[], size_t length,
3 int ( * callback)( int index, int item, void * param),
4 void * param)
5 {
6 int exitCode = 0 ;
7 for ( int i = 0 ; i < length; i ++ ) {
8 exitCode = callback(i, array[i], param);
9 if (exitCode != 0 ) {
10 break ;
11 }
12 }
13 return exitCode;
14 }
15
16 /* APPLICATION CODE */
17 int search ( int index, int item, void * param)
18 {
19 if (item > 5 ) {
20 * ( int * )param = index;
21 return 1 ;
22 } else {
23 return 0 ;
24 }
25 }
26
27 /* (in another function) */
28 int index;
29 int found;
30 found = traverseWith(array, length, & search, & index);
31 if (found) {
32 printf( " Item %d\n " , index);
33 } else {
34 printf( " Not found\n " );
35 }
36
37
注意 search函数的最后一个参数param,callback函数通常用这样一个指针参数来操作它的scope之外的数据,在这里是用来存放索引的值。只有statically scoped language的语言(如C/C++)才需要这样的参数,Lexically scoped languages的语言(如Lisp)支持closure因而不需要这个参数,closure是一个可以调用的对象,它可以保留创建它的那个scope里的信息,Java中的Inner Class就是一个面向对象的closure,因为它可以通过一个内置的引用访问包含它类的所有成员,包括private成员。
可以看到上面的callback函数是通过一个函数指针实现的,Java不支持函数指针,那么再Java中如何来实现 callback函数呢?
Jave支持Interface,利用它我们可以实现callback的效果。技巧就是把我们要调用的callback函数封装在一个简单的接口里。任何实现这个接口的object都可以用来callback. 下面我写的Java版的callback.
2 import java.util.Collections;
3 import java.util.List;
4 import java.util.Arrays;
5
6 interface Matcher < T >
7 {
8 // test if t meets certain requirement, index is the index of t in a List
9 public boolean matches( int index, T t);
10 }
11 class MyLib
12 {
13 // Find the fisrt item in list that meets the requirement of matcher
14 public static < T > boolean findFirstMatch(List < T > list, Matcher < T > matcher)
15 {
16 boolean found = false ;
17 for ( int i = 0 ; i < list.size(); i ++ )
18 {
19 if (matcher.matches(i,list.get(i)))
20 {
21 found = true ;
22 break ;
23 }
24 }
25 return found;
26 }
27 }
28 class Value
29 {
30 int val;
31 public Value( int val)
32 {
33 this .val = val;
34 }
35 }
36 public class CallbackAndColsureExample
37 {
38 public static final List < Integer > NUMBERS =
39 Collections.unmodifiableList(Arrays.asList( 1 , 4 , 6 , 10 , 3 , 9 , 7 ));
40 public static void main(String[] args)
41 {
42 final int base = 5 ;
43 final Value index = new Value( - 1 );
44 Matcher < Integer > biggerThanBaseMatcher = new Matcher < Integer > ()
45 {
46 public boolean matches( int idx, Integer val)
47 {
48 if (val > base)
49 {
50 index.val = idx;
51 return true ;
52 }
53 else return false ;
54 }
55 };
56 boolean found = MyLib.findFirstMatch(CallbackAndColsureExample.NUMBERS, biggerThanBaseMatcher);
57 if (found) System.out.println( " item found at index " + String.valueOf(index.val));
58 else System.out.println( " item not found " );
59 }
60 }
我们用Matcher<T>这个接口封装了一个callback函数,在类CallbackAndColsureExample的内部我们用了一个匿名的Inner Class实现了Matcher<T>接口,并定义了一个对象biggerThanBaseMatcher,通过biggerThanBaseMatcher我们就可以调用callback函数了。注意这个Inner Class形成了一个closure, 所以在它的内部可以访问在Outer calss里定义的index.