BeanShell has a few advanced features that we haven't mentioned yet. They will be discussed in this section.
We noted earlier that BeanShell syntax does not require that variables
be declared or defined with their type, and that variables that are
not typed when first used can have values of differing types assigned
to them. In addition to this “loose” syntax, BeanShell
allows a “convenience” syntax for dealing with the
properties of JavaBeans. They may be accessed or set as if they were
data members. They may also be accessed using the name of the property
enclosed in quotation marks and curly brackets. For example, the following
statement are all equivalent, assuming btn
is
a JButton
instance:
b.setText("Choose"); b.text = "Choose"; b{"text"} = "Choose";
The last form can also be used to access a key-value pair of a
Hashtable
object.
BeanShell uses special keywords to refer to variables or methods defined in the current or an enclosing block's scope:
The keyword this
refers to the current scope.
The keyword super
refers to the immediately
enclosing scope.
The keyword global
refers to the top-level
scope of the macro script.
The following script illustrates the use of these keywords:
a = "top\n"; foo() { a = "middle\n"; bar() { a = "bottom\n"; textArea.setSelectedText(global.a); textArea.setSelectedText(super.a); // equivalent to textArea.setSelectedText(this.a): textArea.setSelectedText(a); } bar(); } foo();
When the script is run, the following text is inserted in the current buffer:
top middle bottom
As discussed in the macro example in Chapter 14, A Dialog-Based Macro, scripted objects can implicitly implement Java
interfaces such as ActionListener
. For example:
myRunnable() { run() { System.out.println("Hello world!"); } return this; } Runnable r = myRunnable(); new Thread(r).start();
Frequently it will not be necessary to implement all of the methods of
a particular interface in order to specify the behavior of a scripted
object. To prevent BeanShell from throwing exceptions for missing interface methods, implement the invoke()
method,
which is called when an undefined method is invoked on a scripted
object. Typically, the implementation of this method will do nothing,
as in the following example:
invoke(method, args) {}
In addition to the implicit interface definitions described above, BeanShell permits full-blown classes to be defined. Indeed, almost any Java class definition should work in BeanShell:
class Cons { // Long-live LISP! Object car; Object cdr; rplaca(Object car) { this.car = car; } rplacd(Object cdr) { this.cdr = cdr; } }