map socketowner = new hashmap();
map<socket, future<string>> socketowner = new hashmap<socket, future<string>>();
public class socketusermap extends hashmap<socket<future<string>> { } socketusermap socketowner = new socketusermap(); // define a type called "callback" that is a function pointer typedef void (*callback)(int); void dosomething(callback callback) { } // this function conforms to the type defined by callback void callbackfunction(int arg) { } // so a caller can pass the address of callbackfunction to dosomething void usecallback() { dosomething(&callbackfunction); } class stringlist extends arraylist<string> { } class userlist extends arraylist<string> { } ... class someclass { public void validateusers(userlist users) { ... } public userlist lookupall(stringlist names) { ... } }
这个限制要比初看上去严格得多。在小程序中,可能不会有太大差异,但是当程序变大的时候,使用伪类型的需求就会不断地造成问题。如果变量类型是 stringlist,就不能给它分配普通的 list<string>,因为 list<string> 是 stringlist 的超类型,所以不是 stringlist。就像不能把 object 分配给类型为 string 的变量一样,也不能把 list<string> 分配给类型为 stringlist 的变量(但是,可以反过来,例如,可以把 stringlist 分配给类型为 list<string> 的变量,因为 list<string> 是 stringlist 的超类型。)
同样的情况也适用于方法的参数;如果一个方法参数是 stringlist 类型,那么就不能把普通的 list<string> 传递给它。这意味着,如果不要求这个方法的每次使用都使用伪类型,那么根本不能用伪类型作为方法参数,而这在实践当中就意味着在库 api 中根本就不能使用伪类型。而且大多数库 api 都源自本来没想成为库代码的那些代码,所以 “这个代码只是给我自己的,没有其他人会用它” 可不是个好借口(只要您的代码有一点儿用处,别人就有可能会使用它;如果您的代码臭得很,那您可能是对的)。
伪类型会传染
这种 “病毒” 性质是让 c 代码的重用有困难的因素之一。差不多每个 c 包都有头文件,定义工具宏和类型,像 int32、boolean、true、false,诸如此类。如果想在一个应用程序内使用几个包,而它们对于这些公共条目没有使用相同的定义,那么即使要编译一个只包含所有头文件的空程序,之前也要在 “头文件地狱” 问题上花好长时间。如果编写的 c 应用程序要使用许多来自不同作者的不同的包,那么几乎肯定要涉及一些这类痛苦。另一方面,对于 java 应用程序来说,在没有这类痛苦的情况下使用许多甚至更多的包,是非常常见的事。如果包要在它们的 api 中使用伪类型,那么我们可能就要重新经历早已留在痛苦回忆中的问题。
作为示例,假设有两个不同的包,每个包都用伪类型反模式定义了 stringlist,如清单 4 所示,而且每个包都定义了操作 stringlist 的工具方法。两个包都定义了同样的标识符,这一事实已经是不方便的一个小源头了;客户程序必须选择导入一个定义,而另一个定义则要使用完全限定的名称。但是更大的问题是现在这些包的客户无法创建既能传递给 sortlist 又能传递给 reverselist 的对象,因为两个不同的 stringlist 类型是不同的类型,彼此互不兼容。客户现在必须在使用一个包还是使用另一个包之间进行选择,否则他们就必须做许多工作,在不同类型的 stringlist 之间进行转换。对包的作者来说以为方便的东西,成为在所有地方使用这个包的突出障碍,除非在最受限的环境中。
清单 4. 伪类型的使用如何妨碍重用
package a; class stringlist extends arraylist<string> { } class listutilities { public static void sortlist(stringlist list) { } } package b; class stringlist extends arraylist<string> { } class someotherutilityclass { public static void reverselist(stringlist list) { } } ... class client { public void somemethod() { stringlist list = ...; // can't do this listutilities.sortlist(list); someotherutilityclass.reverselist(list); } } public static <k,v> map<k,v> newhashmap() { return new hashmap<k,v>(); } map<socket, future<string>> socketowner = util.newhashmap();
新闻热点
疑难解答
图片精选