成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java 8的Nashorn腳本引擎教程

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

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

[[178990]]

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

使用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 ,所以我們現在跳過jjs。用java代碼來一個簡單的  HelloWorld示例,如下:

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

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

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

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

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

當前Nashorn的策略是遵循ECMAScript規范。 當我們發布JDK 8時,我們將實現ECMAScript 5.1標準。后續的 Nashorn的版本將實現 ECMAScript Edition 6標準。

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

Java調用Javascript 函數

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

如下的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. }; 

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

 

  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 

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

現在我們通過傳遞任意的 Java 對象去調用第二個函數:

 

  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 虛擬機中執行的,我們可以完全利用 nashorn 引擎的 Java API 和外部庫的強大功能。

在 JavaScript 端調用 Java 方法

在 JavaScript 中調用 Java 方法很簡單。首先我們定義一個靜態的 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 類型后我們可直接調用其靜態方法 fun1() 并打印結果到 sout。因為方法是靜態的,所以我們無需創建類實例。

 

  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類型轉換?讓我們用一個簡單的例子來發現。

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

 

  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 類型被轉換為適當的 java 包裝器類。而不是本地javascript對象內部適配器類。請記住,這些類來自于jdk.nashorn.internal,所以你不應該在客戶端使用這些類:

Anything marked internal will likely change out from underneath you.

ScriptObjectMirror

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

下一個示例更改參數類型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對象中的函數。我們首先定義一個JavaScript類型 Person,包含屬性 firstName 、lastName 和函數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 函數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。 讓我們直接進入***的功能:

類型數組

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

 

  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[] 數組的行為像一個真正的 java int 數組。 但當我們試圖添加非整數的值的數組時,Nashorn 會執行隱式類型轉換。 字符串會自動轉換為int,這相當方便。

集合與For Each

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

 

  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

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

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

 

  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 表達式的地方使用函數來替代。

 

  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 進行擴展,在下個例子你將在腳本中創建一個多線程示例:

 

  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 

 

參數重載

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

 

  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 

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

Java Beans

我們不需要常規的用 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 

函數語法

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

 

  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 

數組轉換

有些包時可以直接使用而不必利用 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的數組:

  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[]"); 

調用父類函數

在 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 。創建一個新的 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中執行其它腳本是十分容易的。我們可以load函數載入本地或遠程的腳本。

在我的很多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

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

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

  1. loadWithNewGlobal('script.js'); 

命令行腳本

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

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

總結

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

過去我也發表了一些 文章 是關于如何在 Nashron 引擎中使用 Backbone.js 模型數據的。如果你想要了解更多 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 游戲 引擎

2025-04-17 02:00:00

2011-07-18 12:29:10

2011-07-18 11:23:29

iPhone 游戲 動畫

2011-07-18 11:39:58

iPhone 游戲 引擎

2016-09-26 14:16:18

shell腳本bash

2011-07-20 13:37:14

2011-08-29 15:10:19

JAVALua 腳本

2025-02-04 11:30:10

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩在线视频一区二区三区 | 国产精品日日夜夜 | 日韩免费av | 99精品欧美一区二区三区 | 日本精品网站 | 91资源在线观看 | 成人国产一区二区三区精品麻豆 | 国产精品国产成人国产三级 | 久久国产精品视频 | 91久久精品一区二区三区 | 91精品国产高清一区二区三区 | 91久久久久 | 欧美日韩欧美 | 亚洲a一区二区 | 91亚洲国产 | 伊人影院在线观看 | 国产成人精品一区二区三区视频 | 在线观看精品视频网站 | 久热9 | 91色视频在线观看 | 免费h视频 | 91国语清晰打电话对白 | 亚洲精品一区二三区不卡 | 伦理午夜电影免费观看 | 超碰免费在 | 老司机久久 | 日韩一级免费电影 | 欧美精品久久 | 97中文视频 | 午夜欧美| 97精品一区二区 | 天天舔天天| 久久久久国产成人精品亚洲午夜 | 一区在线观看 | 欧美精三区欧美精三区 | 91精品国产综合久久久动漫日韩 | www,黄色,com | 午夜免费观看网站 | 日韩成人免费av | 一区二区三区四区国产 | 中文字幕日韩欧美一区二区三区 |