偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java 8的Nashorn腳本引擎教程

開發(fā) 后端
本文為了解所有關于 Nashorn JavaScript 引擎易于理解的代碼例子。 Nashorn JavaScript 引擎是Java SE 8的一部分,它與其它像Google V8 (它是Google Chrome 和Node.js的引擎)的獨立引擎相互競爭。 Nashorn 擴展了Java在JVM上運行動態(tài)JavaScript腳本的能力。

本文為了解所有關于 Nashorn JavaScript 引擎易于理解的代碼例子。 Nashorn JavaScript 引擎是Java SE 8的一部分,它與其它像Google V8 (它是Google Chrome 和Node.js的引擎)的獨立引擎相互競爭。 Nashorn 擴展了Java在JVM上運行動態(tài)JavaScript腳本的能力。

[[178990]]

在接下來的大約15分鐘里,您將學習如何在 JVM 上動態(tài)運行 JavaScript。 通過一些簡短的代碼示例演示最近 Nashorn 的語言特性。 學習 Java 與 JavaScript 的相互調用。***包括如何在日常的 Java 業(yè)務中整合動態(tài)腳本。

使用Nashorn

Nashorn javascript 引擎要么在java程序中以編程的方式使用要么在命令行工具jjs使用,jjs在目錄$JAVA_HOME/bin中。如果你準備建立一個jjs的符號鏈接,如下:

 

  1. $ cd /usr/bin 
  2. $ ln -s $JAVA_HOME/bin/jjs jjs 
  3. $ jjs 
  4. jjs> print('Hello World'); 

本教程關注的是在java代碼中使用 nashorn ,所以我們現(xiàn)在跳過jjs。用java代碼來一個簡單的  HelloWorld示例,如下:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval("print('Hello World!');");

為了在java中執(zhí)行JavaScript代碼,首先使用原先Rhino (舊版Java中來自Mozilla的引擎)中的包javax.script來創(chuàng)建一個nashorn腳本引擎。.

既可以向上面那樣把JavaScript代碼作為一個字符串來直接執(zhí)行,也可放入一個js腳本文件中,如:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); engine.eval(new FileReader("script.js"));

Nashorn javascript是基于 ECMAScript 5.1 ,但nashorn后續(xù)版本將支持 ECMAScript 6:

當前Nashorn的策略是遵循ECMAScript規(guī)范。 當我們發(fā)布JDK 8時,我們將實現(xiàn)ECMAScript 5.1標準。后續(xù)的 Nashorn的版本將實現(xiàn) ECMAScript Edition 6標準。

Nashorn定義了很多語言和擴展了 ECMAScript標準的API 。接下來我們看看java與JavaScript的通信。

Java調用Javascript 函數(shù)

Nashorn 支持java代碼直接調用定義在腳本文件中JavaScript函數(shù)。你可以把java對象作為函數(shù)的參數(shù)且在調用函數(shù)的java方法中接收返回的數(shù)據(jù)。

如下的JavaScript代碼將會在java端調用:

  1. var fun1 = function(name) { 
  2.     print('Hi there from Javascript, ' + name); 
  3.     return "greetings from javascript"; }; var fun2 = function (object) { print("JS Class Definition: " + Object.prototype.toString.call(object)); 
  4. }; 

為了調用函數(shù),你首先得把腳本引擎轉換為 Invocable。NashornScriptEngine 實現(xiàn)了 Invocable 接口且定義一個調用JavaScript函數(shù)的方法 invokeFunction ,傳入函數(shù)名即可。

 

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); 
  2. engine.eval(new FileReader("script.js")); 
  3.  
  4. Invocable invocable = (Invocable) engine; 
  5.  
  6. Object result = invocable.invokeFunction("fun1""Peter Parker"); 
  7. System.out.println(result); 
  8. System.out.println(result.getClass()); 
  9.  
  10. // Hi there from Javascript, Peter Parker 
  11. // greetings from javascript 
  12. // class java.lang.String 

上述代碼的執(zhí)行將在控制臺打印三行信息。調用 print 函數(shù)將輸出內容通過管道送到 System.out 控制臺,因此我們首先看到的是 JavaScript打印的信息。

現(xiàn)在我們通過傳遞任意的 Java 對象去調用第二個函數(shù):

 

  1. invocable.invokeFunction("fun2"new Date()); 
  2. // [object java.util.Date] 
  3.  
  4. invocable.invokeFunction("fun2", LocalDateTime.now()); 
  5. // [object java.time.LocalDateTime] 
  6.  
  7. invocable.invokeFunction("fun2"new Person()); 
  8. // [object com.winterbe.java8.Person] 

你可以傳遞任意 Java 對象而不會在 JavaScript 這邊丟失類型信息。因為腳本本身是在 JVM 虛擬機中執(zhí)行的,我們可以完全利用 nashorn 引擎的 Java API 和外部庫的強大功能。

在 JavaScript 端調用 Java 方法

在 JavaScript 中調用 Java 方法很簡單。首先我們定義一個靜態(tài)的 Java 方法:

 

  1. static String fun1(String name) { 
  2.     System.out.format("Hi there from Java, %s", name); 
  3.     return "greetings from java"

JavaScript 可通過 Java.type API 來引用 Java 類。這跟在 Java 類中引入其他類是類似的。當定義了 Java 類型后我們可直接調用其靜態(tài)方法 fun1() 并打印結果到 sout。因為方法是靜態(tài)的,所以我們無需創(chuàng)建類實例。

 

  1. var MyJavaClass = Java.type('my.package.MyJavaClass'); 
  2. var result = MyJavaClass.fun1('John Doe'); 
  3. print(result); 
  4. // Hi there from Java, John Doe 
  5. // greetings from java 

 

當調用java 方法時,Nashorn怎樣處理原生JavaScript類型與java類型轉換?讓我們用一個簡單的例子來發(fā)現(xiàn)。

下面的java方法簡單打印實際的類方法參數(shù)的類型:

 

  1. static void fun2(Object object) { 
  2.     System.out.println(object.getClass()); 

為了解引擎如何處理類型轉換,我使用不同JavaScript類型來調用java方法:

 

  1. MyJavaClass.fun2(123); 
  2. // class java.lang.Integer 
  3.  
  4. MyJavaClass.fun2(49.99); 
  5. // class java.lang.Double 
  6.  
  7. MyJavaClass.fun2(true); 
  8. // class java.lang.Boolean 
  9.  
  10. MyJavaClass.fun2("hi there"
  11. // class java.lang.String 
  12.  
  13. MyJavaClass.fun2(new Number(23)); 
  14. // class jdk.nashorn.internal.objects.NativeNumber 
  15.  
  16. MyJavaClass.fun2(new Date()); 
  17. // class jdk.nashorn.internal.objects.NativeDate 
  18.  
  19. MyJavaClass.fun2(new RegExp()); 
  20. // class jdk.nashorn.internal.objects.NativeRegExp 
  21.  
  22. MyJavaClass.fun2({foo: 'bar'}); 
  23. // class jdk.nashorn.internal.scripts.JO4 

 

原始的javascript 類型被轉換為適當?shù)?nbsp;java 包裝器類。而不是本地javascript對象內部適配器類。請記住,這些類來自于jdk.nashorn.internal,所以你不應該在客戶端使用這些類:

Anything marked internal will likely change out from underneath you.

ScriptObjectMirror

當使用ScriptObjectMirror把本地JavaScript對象傳入時,實際上是有一個java對象表示JavaScript 對象。 ScriptObjectMirror 實現(xiàn)了接口與jdk.nashorn.api內部的映射。這個包下的類目的就是用于客戶端代碼使用。

下一個示例更改參數(shù)類型Object為ScriptObjectMirror,因此我們能獲取到傳入JavaScript中對象的一些信息:

 

  1. static void fun3(ScriptObjectMirror mirror) { 
  2.     System.out.println(mirror.getClassName() + ": " + 
  3.         Arrays.toString(mirror.getOwnKeys(true))); 

當我們把傳遞對象hash到方法中,在Java端就能訪問這些屬性:

 

  1. MyJavaClass.fun3({ 
  2.     foo: 'bar'
  3.     bar: 'foo' 
  4. }); 
  5.  
  6. // Object: [foo, bar] 

 

我們也可以在Java端調用JavaScript對象中的函數(shù)。我們首先定義一個JavaScript類型 Person,包含屬性 firstName 、lastName 和函數(shù)getFullName。

 

  1. function Person(firstName, lastName) { 
  2.     this.firstName = firstName; 
  3.     this.lastName = lastName; 
  4.     this.getFullName = function() { 
  5.         return this.firstName + " " + this.lastName; 
  6.     } 

javascript 函數(shù)getFullName 能被 ScriptObjectMirror 的callMember()調用。

 

  1. static void fun4(ScriptObjectMirror person) { 
  2.     System.out.println("Full Name is: " + person.callMember("getFullName")); 

當我們傳入一個新的person給java 方法時,我們能在控制臺看到預期結果:

 

  1. var person1 = new Person("Peter""Parker"); 
  2. MyJavaClass.fun4(person1); 
  3.  
  4. // Full Name is: Peter Parker 

語言擴展

Nashorn 定義一系列的語言和擴展了 ECMAScript 標準的API。 讓我們直接進入***的功能:

類型數(shù)組

原始javascript 數(shù)組時無類型的。 Nashorn 運行你在JavaScript中使用java數(shù)組:

 

  1. var IntArray = Java.type("int[]"); 
  2.  
  3. var array = new IntArray(5); 
  4. array[0] = 5
  5. array[1] = 4
  6. array[2] = 3
  7. array[3] = 2
  8. array[4] = 1
  9.  
  10. try { 
  11.     array[5] = 23
  12. catch (e) { 
  13.     print(e.message);  // Array index out of range: 5 
  14.  
  15. array[0] = "17"
  16. print(array[0]);  // 17 
  17.  
  18. array[0] = "wrong type"
  19. print(array[0]);  // 0 
  20.  
  21. array[0] = "17.3"
  22. print(array[0]);  // 17 

int[] 數(shù)組的行為像一個真正的 java int 數(shù)組。 但當我們試圖添加非整數(shù)的值的數(shù)組時,Nashorn 會執(zhí)行隱式類型轉換。 字符串會自動轉換為int,這相當方便。

集合與For Each

我們可以使用java的集合來代替數(shù)組。首先定義使用 Java.type定義一個java類型,而后根據(jù)需要創(chuàng)建一個實例。

 

  1. var ArrayList = Java.type('java.util.ArrayList'); 
  2. var list = new ArrayList(); 
  3. list.add('a'); 
  4. list.add('b'); 
  5. list.add('c'); 
  6.  
  7. for each (var el in list) print(el);  // a, b, c

為了遍歷集合和數(shù)組中的元素,Nashorn 引入了 for each 語句。這就像是 Java 的 for 循環(huán)一樣。

這里是一個對集合元素進行遍歷的例子,使用的是 :

 

  1. var map = new java.util.HashMap(); 
  2. map.put('foo''val1'); 
  3. map.put('bar''val2'); 
  4.  
  5. for each (var e in map.keySet()) print(e);  // foo, bar 
  6. for each (var e in map.values()) print(e);  // val1, val2 

 

Lambda 表達式和 Streams

似乎大家都比較喜歡 Lambda 和 Streams —— Nashorn 也是!雖然 ECMAScript 5.1 中缺少 Java 8 Lambda 表達式中的緊縮箭頭的語法,但我們可以在接受 Lambda 表達式的地方使用函數(shù)來替代。

 

  1. var list2 = new java.util.ArrayList(); 
  2. list2.add("ddd2"); 
  3. list2.add("aaa2"); 
  4. list2.add("bbb1"); 
  5. list2.add("aaa1"); 
  6. list2.add("bbb3"); 
  7. list2.add("ccc"); 
  8. list2.add("bbb2"); 
  9. list2.add("ddd1"); 
  10.  
  11. list2 
  12.     .stream() 
  13.     .filter(function(el) { 
  14.         return el.startsWith("aaa"); 
  15.     }) 
  16.     .sorted() 
  17.     .forEach(function(el) { 
  18.         print(el); 
  19.     }); 
  20.     // aaa1, aaa2 

擴展類

Java 的類型可以簡單的通過 Java.extend 進行擴展,在下個例子你將在腳本中創(chuàng)建一個多線程示例:

 

  1. var Runnable = Java.type('java.lang.Runnable'); 
  2. var Printer = Java.extend(Runnable, { 
  3.     run: function() { 
  4.         print('printed from a separate thread'); 
  5.     } 
  6. }); 
  7.  
  8. var Thread = Java.type('java.lang.Thread'); 
  9. new Thread(new Printer()).start(); 
  10.  
  11. new Thread(function() { 
  12.     print('printed from another thread'); 
  13. }).start(); 
  14.  
  15. // printed from a separate thread 
  16. // printed from another thread 

 

參數(shù)重載

方法和函數(shù)可以使用點符號或方括號來進行調用。

 

  1. var System = Java.type('java.lang.System'); 
  2. System.out.println(10);              // 10 
  3. System.out["println"](11.0);         // 11.0 
  4. System.out["println(double)"](12);   // 12.0 

在使用重載的參數(shù)來調用方法時可以傳遞可選參數(shù)來確定具體調用了哪個方法,如 println(double)。

Java Beans

我們不需要常規(guī)的用 getter 或者 setter 來訪問類成員屬性,可直接用屬性名簡單訪問 Java Bean 中的屬性。例如:

 

  1. var Date = Java.type('java.util.Date'); 
  2. var date = new Date(); 
  3. date.year += 1900
  4. print(date.year);  // 2014 

函數(shù)語法

如果只是簡單的一行函數(shù)我們可以不用大括號:

 

  1. function sqr(x) x * x; 
  2. print(sqr(3));    // 9 

屬性綁定

來自不同對象的屬性可以綁定在一起:

 

  1. function sqr(x) x * x; 
  2. print(sqr(3));    // 9 

 

字符串處理

我喜歡字符串裁剪.

  1. print(" hehe".trimLeft()); // hehe print("hehe ".trimRight() + "he"); // hehehe 

在哪里

以防忘記你在哪里:

  1. print(__FILE__, __LINE__, __DIR__); 

Import 的范圍

有時,這在一次性導入多個java 包時非常有用。我們可以使用JavaImporter并結合with,在with塊范圍內引用:

  1. var imports = new JavaImporter(java.io, java.lang); 
  2. with (imports) { 
  3.     var file = new File(__FILE__); 
  4.     System.out.println(file.getAbsolutePath()); 
  5.     // /path/to/my/script.js 

數(shù)組轉換

有些包時可以直接使用而不必利用 Java.type 或JavaImporter引入,如 java.util:

  1. var list = new java.util.ArrayList(); 
  2. list.add("s1"); list.add("s2"); list.add("s3"); 

如下的代碼演示了將java list轉換為JavaScript的數(shù)組:

  1. var jsArray = Java.from(list); 
  2. print(jsArray);                                  // s1,s2,s3 
  3. print(Object.prototype.toString.call(jsArray));  // [object Array] 

其他的方式:

  1. var javaArray = Java.to([35711], "int[]"); 

調用父類函數(shù)

在 JavaScript 中訪問重載的成員會有一點點尷尬,因為 ECMAScript 沒有類似 Java 的 super 關鍵字一樣的東西。所幸的是 Nashorn 有辦法解決。

首先我們在 Java 代碼中定義一個超類:

  1. class SuperRunner implements Runnable { 
  2.     @Override 
  3.     public void run() { 
  4.         System.out.println("super run"); 
  5.     } 

接下來我們在 JavaScript 中重載 SuperRunner 。創(chuàng)建一個新的 Runner 實例時請注意 Nashorn 的擴展語法:其重載成員的語法是參考 Java 的匿名對象的做法。

 

  1. var SuperRunner = Java.type('com.winterbe.java8.SuperRunner'); 
  2. var Runner = Java.extend(SuperRunner); 
  3.  
  4. var runner = new Runner() { 
  5.     run: function() { 
  6.         Java.super(runner).run(); 
  7.         print('on my run'); 
  8.     } 
  9. runner.run(); 
  10.  
  11. // super run 
  12. // on my run 

我們使用Java.super調用了重載方法 SuperRunner.run()。

在JavaScript中執(zhí)行其它腳本是十分容易的。我們可以load函數(shù)載入本地或遠程的腳本。

在我的很多web前端中都使用了 Underscore.js ,因此在Nashorn中我們可以重用 Underscore:

 

  1. load('http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js'); 
  2.  
  3. var odds = _.filter([123456], function (num) { 
  4.     return num % 2 == 1
  5. }); 
  6. print(odds);  // 1, 3, 5

擴展腳本的執(zhí)行是在同一個 JavaScript 上下文中,因此我們可以直接訪問 underscore 變量。記住腳本的加載可能會因為變量名的重疊導致代碼出問題。

我們可以通過將加載的腳本文件放置到一個新的全局上下文來解決這個問題:

  1. loadWithNewGlobal('script.js'); 

命令行腳本

如果你對用 Java 編寫命令行腳本很感興趣的話,可以試試 Nake 。Nake 是一個為 Java 8 Nashorn 準備的簡單 Make 工具。你可以在 Nakefile 文件中定義任務,然后使用 nake — myTask 來運行任務。任務使用 JavaScript 編寫并通過 Nashorn 腳本模式運行,因此你可以讓你的終端應用完全利用 Java 8 API 和其他 Java 庫強大的功能。

對 Java 開發(fā)者而言,編寫命令行腳本從來沒有如此簡單過。

總結

我希望這篇文章對你有用,可以讓你輕松理解 Nashorn JavaScript 引擎。更多關于 Nashorn 的信息請閱讀 這里這里 和 這里. 如果你是要用 Nashorn 編寫 Shell 腳本的話可以參考 這里.

過去我也發(fā)表了一些 文章 是關于如何在 Nashron 引擎中使用 Backbone.js 模型數(shù)據(jù)的。如果你想要了解更多 Java 8 的話可以去看看我的文章 Java 8 Tutorial 和 Java 8 Stream Tutorial.

本文中的示例代碼可以通過 GitHub 獲取,你可以 fork 這個倉庫并通過 Twitter 來給我反饋。

堅持編程!

責任編輯:張燕妮 來源: luke, coyee, CY2
相關推薦

2014-03-26 15:08:33

Java 8腳本引擎

2014-07-14 11:34:53

Java 8Nashorn

2009-04-04 09:42:53

IE8JScript瀏覽器

2014-07-15 14:48:26

Java8

2013-12-06 10:12:49

Android游戲引擎libgdx教程

2014-03-19 11:04:14

Java 8Java8特性

2009-06-30 11:33:55

腳本JSP教程

2013-12-06 09:59:53

Android游戲引擎libgdx教程

2018-08-28 16:02:59

LinuxShellBash

2022-05-30 10:31:34

Bash腳本Linux

2011-07-18 10:53:09

2011-07-18 11:07:12

iPhone 游戲 引擎

2011-07-18 12:29:10

2011-07-18 11:23:29

iPhone 游戲 動畫

2011-07-18 11:39:58

iPhone 游戲 引擎

2025-04-17 02:00:00

2016-09-26 14:16:18

shell腳本bash

2011-07-20 13:37:14

2025-02-04 11:30:10

2010-09-30 11:16:53

J2ME Snake腳
點贊
收藏

51CTO技術棧公眾號