更多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!"
運行效果