在 Nashorn 與 Java API(一) 中介紹了一些如何撰寫 JavaScript 來使用 Java API,語言本身並不是一對一,因而若要進一步使用 Java 的一些特性,就得有一些額外的對應方式。
指定重載方法
實際上方法在 JavaScript 不過是個物件上的特性,為函式實例,因此,除了使用 .
來存在方法之外,也可以使用 []
來取得代表方法的函式:
var System = Java.type('java.lang.System');
System.out.println('Hello, World'); // Hello, World
System.out['println']('Hello, World'); // Hello, World
Java 中支援重載(Overload)方法,例如,System.out
的 println
有多個重載版本,如果你想指定呼叫特定的重載版本,可以使用 []
時指定參數列。例如:
var System = Java.type('java.lang.System');
System.out['println'](3.14); // 3.14
System.out['println(double)'](3.14); // 3.14
System.out['println(int)'](3.14); // 3
實例方法也可以使用這種方式:
var PrintStream = Java.type('java.io.PrintStream');
var file = new PrintStream('test.txt');
file['println(int)'](3.14); // test.txt 中只存 3 這個數值
file.close();
JavaImporter、importPackage、 importClass
Java 中有 import
語法,在 Nashorn 中可以用 Java.type
來模擬 import
特定類別的作用:
var PrintStream = Java.type('java.io.PrintStream');
如果想同時將數個類別或套件放在某個名稱空間下,可以使用 JavaImport
。例如:
var commons = new JavaImporter(java.util, java.lang);
with(commons) {
var lt = Arrays.asList(1, 2, 3);
System.out.println(lt); // [1, 2, 3]
}
Nashorn 內建了 mozilla_compat.js,可以使用 load
載入後,使用 imoprtPackage
或 importClass
,前者相當於在 Java 中 import
時在類別的部份使用 *
,後者用來 import
某個類別。例如:
load('nashorn:mozilla_compat.js');
importClass(java.lang.System);
importPackage(java.util);
System.out.println('Hello, World'); // Hello, World
var lt = Arrays.asList(1, 2, 3);
System.out.println(lt); // [1, 2, 3]
實作介面
如果想要實作介面,可以使用 Java.extend
。例如:
load('nashorn:mozilla_compat.js');
importPackage(java.lang);
var RunDemo = Java.extend(Runnable, {
run: function() {
[1, 2, 3].forEach(print);
}
});
var th = new Thread(new RunDemo());
th.start();
th.join();
不使用 Java.extend
,也可以用類似 Java 的匿名類別實作語法:
load('nashorn:mozilla_compat.js');
importPackage(java.lang);
var r = new Runnable {
run: function() {
[1, 2, 3].forEach(print);
}
};
var th = new Thread(r);
th.start();
th.join();
如果方法的參數型態是個只具備單一抽象方法的介面,可以直接使用函式實作。例如:
var IntStream = Java.type("java.util.stream.IntStream");
var sum = IntStream.of(1, 2, 3, 4, 5, 6)
.filter(function(elem) {
return elem > 2;
})
.sum();
print(sum); // 18
繼承類別
如果是要繼承抽象類別並實作抽象方法,方式與實作介面是類似的:
load('nashorn:mozilla_compat.js');
importPackage(java.util);
var r = new TimerTask {
run: function() {
[1, 2, 3].forEach(print);
}
};
r.run();
var DemoTask = Java.extend(TimerTask, {
run: function() {
[1, 2, 3].forEach(print);
}
});
new DemoTask().run();
然而,如果是繼承非抽象類別,就必須使用 java.extend
:
load('nashorn:mozilla_compat.js');
importPackage(java.lang);
var DemoThread1 = Java.extend(Thread, {
run: function() {
[1, 2, 3].forEach(print);
}
});
new DemoThread1().run();
var DemoThread2 = Java.extend(Thread);
(new DemoThread2 {
run: function() {
[1, 2, 3].forEach(print);
}
}).run();
實際上,Java.extend
每次呼叫後,都會建立一個子類別的型態物件,因此,以下兩種寫法有些不同:
load('nashorn:mozilla_compat.js');
importPackage(java.lang);
var DemoThread1 = Java.extend(Thread, {
run: function() {
[1, 2, 3].forEach(print);
}
});
var DemoThread2 = Java.extend(Thread, {
run: function() {
[1, 2, 3].forEach(print);
}
});
System.out.println(new DemoThread1().getClass() === new DemoThread2().getClass()); // false
var DemoThread = Java.extend(Thread);
var th1 = new DemoThread {
run: function() {
[1, 2, 3].forEach(print);
}
};
var th2 = new DemoThread {
run: function() {
[1, 2, 3].forEach(print);
}
};
System.out.println(th1.getClass() === th2.getClass()); // true
呼叫父類別方法
如果想呼叫父類別建構式並同時重新實作某方法,可以如下:
load('nashorn:mozilla_compat.js');
importPackage(java.lang);
var Th = Java.extend(Thread);
var r = function() {
[1, 2, 3].forEach(function(elem) {
print(elem);
});
};
var th1 = new Th(r) {
run : function() {
Java.super(th1).run();
[4, 5, 6].forEach(function(elem) {
print(elem);
});
}
};
th1.start();
th1.join();
上面的範例也示範了 Java.super
的使用,它可用來呼叫父類別的方法。
從 Java 中執行 JavaScript
要在 Java 中使用 Nashorn 執行 JavaScript 的話,可以如下取得 Nashorn 引擎:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("nashorn");
engine.eval("print('Hello, World!')");
engine.eval(new FileReader("C:\\workspace\\hello.js"));
這是 JSR 223: Scripting for the Java Platform 規範中的東西,你可以在 Oracle 的 Scripting for the Java Platform 找到相關資訊。
實際上,這兩篇〈Nashorn 與 Java API〉的內容,在 Oracle Java Platform, Standard Edition Java Scripting Programmer's Guide 中 3 Using Java From Scripts 就有談到,如果想要瞭解更多如何在 Java 中呼叫 JavaScript,可以進一步參考 2 The Java Scripting API。
專門說明 Nashorn 的 Oracle 文件,則可以在 Java Platform, Standard Edition Nashorn User's Guide 找到。