更多BeanShell内容请点击此处
在 Java 中为了(处理)拥有多个方法的接口而创建“傻瓜”适配器的情况非常得常见。傻瓜适配器的工作就是带着存根(空方法体)实现接口中的所有方法,允许开发者扩展适配器并且只是重写感兴趣的方法。
我们在之前的讨论中暗示过 BeanShell 可以处理只是实现实际被使用的方法子集的脚本接口,而 BeanShell 的确就是这样。你可以在 BeanShell 中自由地只是编写你期望调用的接口方法的脚本。离开了实际被调用的方法的惩罚是调用者会接收到一个特殊的 run-time 异常: java.lang.reflect.UndeclaredThrowableException。
UndeclaredThrowableException 是 Java 语法 API 中的一个典型,使动态接口成为可能。就是说一个接口抛出一个没有被方法签名指定的检查异常类型。那是在 Java 编译环境中不太会发生的情况。所以 Java 反射 API 通过在这个特殊的未检查(RuntimeException)类型里包装检查异常的方式将它抛出。你可以通过使用 exception 的 getCause() 方法获得隐含的错误,这样做将显示 BeanShell 的 EvalError 异常,报出没有找到正确签名的脚本方法。
invoke() 元方法
BeanShell 为带有大量方法的脚本接口提供一个非常简单的速记机制。你可以在任何脚本上下文中实现特殊方法 invoke(name, args)。invoke() 方法被调用来处理未被定义的接口的任何方法的调用。
示例代码
- mouseHandler = new MouseListener() {
- mousePressed( event ) {
- print("mouse button pressed");
- }
- invoke( method, args ) {
- print("Undefined method of MouseListener interface invoked:" + name +", with args: "+args );
- }
- };
- JFrame jf = new JFrame();
- int a10 = Toolkit.getDefaultToolkit().getScreenSize().width; // 取得屏幕长度
- int b10 = Toolkit.getDefaultToolkit().getScreenSize().height; // 取得屏幕宽度
- jf.setLocation((a10 - 500) / 2, (b10 - 300) / 2); // 设定位置(屏幕中心)
- jf.setTitle("窗口"); // 设定标题
- jf.setSize(500, 300); // 设定大小
- jf.setResizable(false); // 设定不能缩放
- jf.setVisible(true); // 设定显示
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设定在点关闭后关闭窗口
- jf.addMouseListener(mouseHandler);
运行效果
呈现出的窗口
将你的鼠标移到窗口内,或者点击窗口空白处来观察控制台的变化
在上面的例子中我们忽视了 MouseListener 接口里五个方法中的四个方法。他们将会被 invoke() 方法处理,简单地打印方法名和他的参数。不管怎样,既然 mousePressed() 方法被定义了,它就会被接口调用。
这是一个更实际的例子,可谓性手拈来。在解析一个 XML 文档时,让我们使用 invoke() 方法来打印通过 Java SAX API 接口 ContentHandler 调用的方法名称。
示例代码
- import javax.xml.parsers.*;
- import org.xml.sax.InputSource;
- factory = SAXParserFactory.newInstance();
- saxParser = factory.newSAXParser();
- parser = saxParser.getXMLReader();
- parser.setContentHandler( this );
- invoke( name, args ) {
- print( name );
- }
- parser.parse( new InputSource(bsh.args[0]) );
通过运行 XML 文件脚本作为参数,我们可以看到几打或者如同这样 SAX API 的方法通过文档的结构被运行起来,无需为它们每个方法写空方法。
- 提示:
- 你可以直接在你自己的范围或者也可以是全局的范围里使用 invoke(name, args)元方法,这样你可以自己任意处理
- “unknown”方法的调用,也许是实现你自己的“虚拟”命令。试着在命令行里打如下的内容:
- invoke(name,args) { print("Command: "+name+" invoked!"); }
- noSuchMethod(); // 打印 "Command: noSuchMethod() invoked!"
运行效果
本文转自 tongqiuyan 51CTO博客,原文链接:http://blog.51cto.com/tongqiuyan/762599