2012-09-21

importPackageを使った場合、Javaクラスは必要になってから取り込まれる

JavaパッケージをimportPackageやJavaImporterで取り込むと、 パッケージに属する全クラスが一度に取り込まれるのでは、 という勝手なイメージを抱いていた。が、実際はそのようなことはなかった。
以下のスクリプトで確認できる通り、パッケージを取り込んだ時点では、 クラスの取り込みは行われない。取り込んだパッケージに属するクラスの名前が指定された時に、 初めて対象のクラスが取り込まれる。
この仕組みの代償として、パッケージを取り込んだグローバルスコープやJavaImporterオブジェクトは、 for (var key in obj) でループした時点ではkeyに名前が渡されなかったとしても、 名前を指定してアクセスした時は値が返ってくる、という予測しにくい動きをするので、 複数のスクリプトファイルで作業している時は混乱を招くかもしれない。

1. 実行するスクリプト(java-importer.js):
var topLevel = this;
var stdout = java.lang.System.out;

// オブジェクトに定義された名前を出力する関数
function dump(obj) {
    var keys = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            keys.push(key);
        }
    }
    stdout.println("[" + keys + "]");
}

// importPackageでパッケージを取り込む
(function() {
    importPackage(java.util);
    importClass(java.io.File);

    var list = new ArrayList();
    list.add(new File("."));
    list.add(new File("java-importer.js"));
    list.add(new File("js.jar"));
    stdout.println(list); // [., java-importer.js, js.jar]
})();
dump(topLevel); // [importer,dump,stdout,topLevel,File,ArrayList]

stdout.println("LinkedList" in topLevel); // true
stdout.println(!!topLevel.HashMap); // true
dump(topLevel); // [importer,dump,stdout,topLevel,File,ArrayList,LinkedList,HashMap]

// JavaImporterでパッケージを取り込む
var importer = JavaImporter(
    java.net,
    java.nio.charset.Charset
);
dump(importer); // [Charset]

stdout.println("URL" in importer); // true
stdout.println("" + importer.URLDecoder); // [JavaClass java.net.URLDecoder]
dump(importer); // [Charset,URL,URLDecoder]

2. 実行する:
>java -classpath .;js.jar org.mozilla.javascript.tools.shell.Main -w -debug java-importer.js
[., java-importer.js, js.jar]
[importer,dump,stdout,topLevel,File,ArrayList]
true
true
[importer,dump,stdout,topLevel,File,ArrayList,LinkedList,HashMap]
[Charset]
true
[JavaClass java.net.URLDecoder]
[Charset,URL,URLDecoder]

0 件のコメント:

コメントを投稿