Nashorn 支持java代码直接调用定义在脚本文件中JavaScript函数。你可以把java对象作为函数的参数且在调用函数的java方法中接收返回的数据。
如下的JavaScript代码将会在java端调用: var fun1 = function(name) { print('Hi there from Javascript, ' + name); return "greetings from javascript";
};
var fun2 = function (object) { print("JS Class Definition: " + Object.prototype.toString.call(object));
};
为了调用函数,你首先得把脚本引擎转换为 Invocable。NashornScriptEngine 实现了 Invocable 接口且定义一个调用JavaScript函数的方法 invokeFunction ,传入函数名即可。
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("fun1", "Peter Parker");
System.out.println(result);
System.out.println(result.getClass());
// Hi there from Javascript, Peter Parker
// greetings from javascript
// class java.lang.String
上述代码的执行将在控制台打印三行信息。调用 print 函数将输出内容通过管道送到 System.out 控制台,因此我们首先看到的是 JavaScript打印的信息。
现在我们通过传递任意的 Java 对象去调用第二个函数:
invocable.invokeFunction("fun2", new Date());
// [object java.util.Date]
invocable.invokeFunction("fun2", new Person());
// [object com.winterbe.java8.Person]
你可以传递任意 Java 对象而不会在 JavaScript 这边丢失类型信息。因为脚本本身是在 JVM 虚拟机中执行的,我们可以完全利用 nashorn 引擎的 Java API 和外部库的强大功能。
在 JavaScript 端调用 Java 方法
在 JavaScript 中调用 Java 方法很简单。首先我们定义一个静态的 Java 方法: static String fun1(String name) {
System.out.format("Hi there from Java, %s", name); return "greetings from java";
}
JavaScript 可通过 Java.type API 来引用 Java 类。这跟在 Java 类中引入其他类是类似的。当定义了 Java 类型后我们可直接调用其静态方法 fun1() 并打印结果到 sout。因为方法是静态的,所以我们无需创建类实例。 var MyJavaClass = Java.type('my.package.MyJavaClass');
var result = MyJavaClass.fun1('John Doe'); print(result);
// Hi there from Java, John Doe
// greetings from java
当调用java 方法时,Nashorn怎样处理原生JavaScript类型与java类型转换?让我们用一个简单的例子来发现。
下面的java方法简单打印实际的类方法参数的类型: staticvoidfun2(Object object) {
System.out.println(object.getClass());
}
为了解引擎如何处理类型转换,我使用不同JavaScript类型来调用java方法:
MyJavaClass.fun2(123);
// classjava.lang.Integer
我们可以使用java的集合来代替数组。首先定义使用 Java.type定义一个java类型,而后根据需要创建一个实例。 var ArrayList = Java.type('java.util.ArrayList'); varlist = new ArrayList(); list.add('a'); list.add('b'); list.add('c');
for each (var el in list) print(el); // a, b, c
为了遍历集合和数组中的元素,Nashorn 引入了 for each 语句。这就像是 Java 的 for 循环一样。
这里是一个对集合元素进行遍历的例子,使用的是 : var map = new java.util.HashMap();
map.put('foo', 'val1');
map.put('bar', 'val2');
for each (var e in map.keySet()) print(e); // foo, bar
for each (var e in map.values()) print(e); // val1, val2
Java 的类型可以简单的通过 Java.extend 进行扩展,在下个例子你将在脚本中创建一个多线程示例: var Runnable = Java.type('java.lang.Runnable'); var Printer = Java.extend(Runnable, {
run: function() { print('printed from a separate thread');
}
});
var Thread = Java.type('java.lang.Thread'); new Thread(new Printer()).start();
new Thread(function() { print('printed from another thread');
}).start();
// printed from a separate thread
// printed from another thread
参数重载
方法和函数可以使用点符号或方括号来进行调用。
var System = Java.type('java.lang.System');
System.out.println(10); // 10
System.out["println"](11.0); // 11.0
System.out["println(double)"](12); // 12.0
在使用重载的参数来调用方法时可以传递可选参数来确定具体调用了哪个方法,如 println(double)。
Java Beans
我们不需要常规的用 getter 或者 setter 来访问类成员属性,可直接用属性名简单访问 Java Bean 中的属性。例如: var Date = Java.type('java.util.Date'); var date = new Date();
date.year += 1900;
print(date.year); // 2014
函数语法
如果只是简单的一行函数我们可以不用大括号:
function sqr(x) x * x; print(sqr(3)); // 9
属性绑定
来自不同对象的属性可以绑定在一起: var o1 = {}; var o2 = { foo: 'bar'};
Object.bindProperties(o1, o2);
print(o1.foo); // bar
o1.foo = 'BAM'; print(o2.foo); // BAM
有时,这在一次性导入多个java 包时非常有用。我们可以使用JavaImporter并结合with,在with块范围内引用: var imports = new JavaImporter(java.io, java.lang);
with (imports) { var file = new File(__FILE__);
System.out.println(file.getAbsolutePath());
// /path/to/my/script.js
}
var runner = new Runner() {
run: function() {
Java.super(runner).run(); print('on my run');
}
}
runner.run();
// super run
// on my run
我们使用Java.super调用了重载方法 SuperRunner.run()。
在JavaScript中执行其它脚本是十分容易的。我们可以load函数载入本地或远程的脚本。
在我的很多web前端中都使用了 Underscore.js ,因此在Nashorn中我们可以重用 Underscore:
load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js');
var odds = _.filter([1, 2, 3, 4, 5, 6], function (num) { return num % 2 == 1;
});