java se 8 新增主要功能
2、原始java模块系统(“项目jigsaw”)将简化应用程序的构建、包装以及部署,让一个完全模块化的java平台能在服务器、客户和嵌入式系统上进行定制化部署。
3、在jvm上的javascript改进,包括一个为jvm优化的全新javascript引擎nashorn和全面的java / javascript互操作性。
4、具有javafx 3.0形式的下一代java客户端。包括多点触摸功能的现代设备支持。
5、完成的hotspot / jrockit jvm集聚项目,包括性能增强和第二代的java flight recorder。
其中,笔者最关心的是第三条,即jvm对javascript的改进。它的核心组件是javascript引擎nashorn,它实现了java与javascript互操作性。nashorn一词与rhino类似,汉语意思均为犀牛。而巧合的是,rhino就是javascript引擎,它的目的就是实现java与javascript的互操作性。那么rhino究竟是什么呢?为什么说nashorn是新一代javascript引擎?rhino有什么特性?rhino与java及javascript有什么关系呢?本文将会为您一一解答。
什么是rhino?
rhino 是javascript 的一种基于java的实现,原先由mozilla开发,现在被集成进入jdk 6.0。下面这两行代码恰好说明了这一点。
import sun.org.mozilla.javascript.internal.context;
import sun.org.mozilla.javascript.internal.scriptable;
rhino汉语意思为犀牛,它的名字来源于 o'reilly 关于 javascript 的书的封面,如图一所示。
图一 “犀牛“的来源
rhino的特点如下:
javascript 1.5的全部特性
◆ 允许使用脚本直接操作java
◆ 提供javascript shell执行其它javascript脚本
◆ 提供javascript编译器将javascript源程序转换成java类文件
rhino相关背景
rhino的历史可追溯到1997 年。netscape计划开发java版的navigator,即javagator。它也就是 rhino 的前身。虽然 javagator 未能开花结果,但是rhino,作为netscape 对 javascript 的移植语言,经过时间考验存活了下来。
如今,随着 rhino 开放源代码,越来越多的开发者参与了 rhino 的开发。随着rhino的愈加成熟,越来越多的用户选择使用了rhino。
rhino语言特点
java是一种面对对象的编译型语言。它首先将源代码编译成二进制字节码(bytecode),然后依赖各种不同平台上的虚拟机来解释执行字节码,从而实现了“一次编译、到处执行”的跨平台特性。
javascript是一种动态、弱类型、基于原型的客户端脚本语言。javascript 包括一个基于对象的 api,称为文档对象模型(document object model)或 dom,用以访问和操作 web 页面的内容,给html网页添加动态功能。
rhino是一个介于java与javascript之间的语言。它的基础是 java 语言,这使得它简单易学,但相比于javascript脚本语言来说,它又太过复杂。不过,rhino 的主要缺点也正是它的强大之处,rhino 是一种轻量级的、功能强大的脚本语言。rhino 使用原型而不是类,这使它比很多脚本语言更适合开发 gui 应用程序,在考虑性能和风格等因素时更是如此。
rhino语言特点的优缺点
一方面,作为一种动态类型的、基于原型的脚本语言,rhino借用了很多javascript语法。比如,rhino不再使用语句结束符( ; ),放宽了变量声明规则,并且极大地简化了修改和检索对象属性的语法。另一方面,作为javascript 的java实现,rhino语法非常类似于java编程语言。比如,rhino采用了与 java 编程语言相似的循环和条件结构,并且遵循类似的语法模式来表示这些结构。
rhino 和 java 语言之间有一些显著的区别。rhino 是一种基于原型的(prototype-based)语言,而不是一种基于类的(class-based)语言。rhino中,函数和变量的声明中看不到类型,取而代之的是,使用 function关键字声明函数,使用 var关键字声明局部变量。
rhino的原始想法是将javascript 编译成java字节码执行,即采用编译执行的方式。由于由于jvm存在垃圾收集、编译和装载过程的开销过大等限制,rhino采用了解释执行的方式。
如何下载rhino安装包
用户可以从官网http://www.mozilla.org/rhino/ 下载rhino,笔者下载的版本为rhino1.7r3.zip。
其中,主要的目录与文件的如下:
src:rhino相关jar包对应的源代码
javadoc:rhino相关jar包对应的java说明文档
examples:rhino相关示例
build.xml:rhino工程对应的ant文件
js.jar:rhino对应的jar包
rhino环境配置
在使用之前,我们需要配置环境及运行js脚本。具体如下:
1、将下载包中的js.jar文件加入系统classpath中。
2、运行js解释器java org.mozilla.javascript.tools.shell.main。进入交互模式:
rhino 1.7 release 3 2011 05 09
js>
注:第一行为js解释器的版本号,后面跟着提示符 js>
下面我们将利用js shell,使用javascript操纵java对象。
javascript操纵java对象
1、rhino如何访问java包与类文件
java语法规定,任何代码都必须以class文件的形式存在,而每个class文件必须属于一个package,默认为default。而javascript并没有类似package的层级结构概念,那么如何使用rhino访问java类文件呢?
rhino定义了一个top-level变量packages。变量packages对应的所有属性均对应java包名。比如,我们需要访问某一个java的package com.example。
js> packages.com.example
[javapackage com.example]
简单起见,我们也可以去掉变量packages,直接输入java包名。因此,上述package com.example等价与com.example,如下:
js> com.example
刚才演示了如何通过js shell访问java包,访问java类的方式类似。假如我们需要访问标准的java 文件类java.io.file,如下。
js> java.io.file
[javaclass java.io.file]
或者,为避免输入全名,我们先导入包,然后输入class类名,如下:
js> importpackage(java.io)
js> file
这里的importpackage(java.io),在效果上等价于java声明import java.io.*; 不同的是,java会隐式import java.lang.*,而rhino不会。因为rhino定义的对象boolean, math, number, object, string等与java语法完全不同,两者无法等价。
这里需要注意的是,rhino对该语法的错误处理机制,当被访问的类存在时,rhino加载该class,而当其不存在时,则把它当成package名称,而并不会报错。例如,当访问一个不存在的类com.example.aaa时,输入如下。
js> com.example.aaa
[javapackage com.example.aaa]
仅当访问类aaa时,rhino才会报错。
2、rhino如何与java对象交互
与java类似,rhino使用new操作符创建对象。
js> new java.util.date()
thu nov 03 16:19:04 cst 2011
可以使用javascript变量存储java对象,并调用其方法,如下:
js> f = new java.io.file("sample.txt")
sample.txt
js> f.isdirectory()
false
对于static方法与变量,调用如下:
js> java.lang.math.pi
3.141592653589793
js> java.lang.math.cos(0)
1
在javascript中,方法本身就是对象,这一点与java不同。我们可以通过下列方式查看方法的重载:
js> f.listfiles
function listfiles() {/*
java.io.file[] listfiles()
java.io.file[] listfiles(java.io.filenamefilter)
java.io.file[] listfiles(java.io.filefilter)
*/}
输出中列出三个重载方法。第一个为无参函数,第二与第三个对应的参数分别为filenamefilter与filefilter。
另一个比较有意思的特点是通过构造for..in,查看对象对应的所有方法与变量。如下:
js> for (i in f) { print(i) }
exists
parentfile
mkdir
tostring
wait
[44 others]
这里列出的方法一部分来自于父类,比如wait来自父类java.lang.object。
对于javabean,rhino也提供按名字访问的简单方式。比如,通过下面这种方式,我们就可以调用file对象的getname与isdirectory方法:
js> f.name
test.txt
js> f.directory
3、rhino如何实现java接口
javascript当中,方法本身就是对象。下面我们通过javascript语法{propertyname: value}声明一个javascript方法,并调用该方法如下:
js> obj = { run: function () { print("\nrunning"); } }
[object object]
js> obj.run()
running
现在我们构造一个javascript对象,实现runnable接口。并将该对象作为参数,构造一个新的线程,并启动该线程。
js> r = new java.lang.runnable(obj);
adapter1@291aff
js> t = new java.lang.thread(r)
thread[thread-0,5,main]
js> t.start()
js>
running
最后的js>提示符与新线程的打印输出running的先后顺序是随机的,取决于线程的调度策略。
从后端的处理流程来讲,rhino首先为runnable接口的实现类生成java字节码文件。然后调用javascript对象定义的run方法。
4、rhino如何创建java 数组
rhino使用java的发射机制生成数组。下面是生成2个string对象的代码:
js> array = java.lang.reflect.array.newinstance(java.lang.string, 2);
[ljava.lang.string;@a20892
js> array[0] = "double"
double
js> array[1] = "life"
life
js> array[0] + array[1]
doublelife
js>
5、rhino如何捕获与处理异常
与java类似,rhino使用try...catch关键字处理异常。
js> function classforname(name) {
try {
return java.lang.class.forname(name);
} catch (e if e.javaexception instanceof java.lang.classnotfoundexception) {
print("class " + name + " not found");
} catch (e if e.javaexception instanceof java.lang.nullpointerexception) {
print("class name is null");
}
} > > > > > > > >
js> classforname("nonexistingclass");
class nonexistingclass not found
js> classforname(null);
class name is null
6、rhino如何调用js文件
当然,除了在命令行的方式,我们还可以使用操纵javascript文件。下面是一段javascript代码,主要目的是判断该数是否为质数。代码如下:
function isprime (num)
{
if (num <= 1) {
print("enter an integer no less than 2.")
return false
var prime = true
var sqrroot = math.round(math.sqrt(num))
for (var n = 2; prime & n <= sqrroot; ++n) {
prime = (num % n != 0)
return prime
}
我们保存文件为c:\isprime.js。然后我们需要调用load方法加载该脚本。最后,我们可以调用isprime方法来判断是否为质数。
js> load("c:/isprime.js")
js> isprime(33);
false
js> isprime(31)
true
需要注意的是,注意:文件分隔符需要调整,是“/”而不是“\”。
上述部分示例可以参见rhino官方网站。另外examples目录下很多例子都值得参考与学习。
刚才使用javascript操纵java对象。接下来我们看看如何使用java程序访问javascript
java对象操纵javascript
下面是一段java代码,用来运行数学表达式。代码如下:
package com.example;
import sun.org.mozilla.javascript.internal.context;
import sun.org.mozilla.javascript.internal.scriptable;
publicclass test {
publicstaticvoid main(string[] args) {
context cx = context.enter();
scriptable scope = cx.initstandardobjects();
string str = "3/(1+2)";
object result = cx.evaluatestring(scope, str, null, 1, null);
system.out.println(str + "=" + context.tonumber(result));
} finally {
context.exit();
运行java com.example.test,输出结果如下:
3/(1+2)=1.0
之所以是1.0而不是1,是因为context.tonumber(result)返回的类型为double。另一个值得注意的是,这里import的package属于jdk 6.0。因此,在不需要rhino提供的js.jar,该程序仍能独立运行。
虽然rhino作为javascript运行时,功能非常强大,但在性能上却无法与其他的javascript运行时(比如google chrome的v8 javascript engine)相提并论。值得注意的是,jruby专家charles oliver nutter也开始参与rhino项目中,以提升rhino javascript运行时的速度,进而实现与v8的竞争。而oracle在对jvm上的javascript改进与优化,我们有理由期待,在未来,新一代javascript运行时nashorn的速度将会得到极大的提升。
本文出自seven的测试人生公众号最新内容请见作者的github页:http://qaseven.github.io/