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;
    }
}