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/