熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Javascript >> 正文

Java SE 6之腳本引擎 讓程序如虎添翼

2022-06-13   來源: Javascript 
現在Java SE 已經發布在明年Java SE 也將發布Java SE 較Java SE有了很大的改進它的功能更強而且是專為Vista所設計這就意味著Java SE 將是Vista上的最佳選擇而Java SE 所提供的最眾多的新功能必將成為它的最大賣點

  Java SE 最引人注目的新功能之一就是內嵌了腳本支持在默認情況下Java SE 只支持JavaScript但這並不以為著Java SE 只能支持JavaScript在Java SE 中提供了一些接口來定義一個腳本規范也就是JSR通過實現這些接口Java SE 可以支持任意的腳本語言(如PHP或Ruby)

  運行第一個腳本程序

  在使用Java SE 運行腳本之前必須要知道你的Java SE 支持什麼腳本語言在javaxscript包中有很多的類但這些類中最主要的是ScriptEngineManager可以通過這個類得到當前Java SE 所支持的所有腳本如下面例子將列出所有可以使用的腳本引擎工廠

import javaxscript*;
import javaio*;
import javautil*;
import static javalangSystem*;
public class ListScriptEngines
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 得到所有的腳本引擎工廠
  List<ScriptEngineFactory> factories = managergetEngineFactories();
  // 這是Java SE 和Java SE 的新For語句語法
  for (ScriptEngineFactory factory: factories)
  {
   // 打印腳本信息
   outprintf(Name: %s%n +
    Version: %s%n +
    Language name: %s%n +
    Language version: %s%n +
    Extensions: %s%n +
    Mime types: %s%n +
    Names: %s%n
    factorygetEngineName()
    factorygetEngineVersion()
    factorygetLanguageName()
    factorygetLanguageVersion()
    factorygetExtensions()
    factorygetMimeTypes()
    factorygetNames());
   // 得到當前的腳本引擎
   ScriptEngine engine = factorygetScriptEngine();
  }
 }
}
  上面的例子必須要在Java SE 中編譯其中import static javalangSystem*是新的語法將System中的所有靜態成員進行引用以後就可以直接使用outin或err了

  通過運行java ListScriptEngines將顯示如下信息

Name: Mozilla Rhino
Version: release
Language name: ECMAScript
Language version:
Extensions: [js]
Mime types: [application/javascript application/ecmascript text/javascript text/ecmascript]
Names: [js rhino JavaScript javascript ECMAScript ecmascript]
  在最下面一行是腳本的別名也就是使用它們中的任意一個都可以得到一個具體的腳本引擎有種方法

  ·根據擴展名得到腳本引擎

ScriptEngine engine = managergetEngineByExtension(js);
  getEngineByExtension的參數就是Extensions:[js]中[…]裡的部分

  ·根據Mime類型得到腳本引擎

ScriptEngine engine = managergetEngineByMimeType(text/javascript);
  getEngineByMimeType的參數可以是Mime types: [application/javascript application/ecmascript text/javascript text/ecmascript]中的任何一個可以將text/javascript改成text/ecmascript

  ·根據名稱得到腳本引擎

ScriptEngine engine = managergetEngineByName(javascript);
  getEngineByName後的參數可以是Names: [js rhino JavaScript javascript ECMAScript ecmascript]中的任何一個如可以將javascript改成ecmascript

  上面已經討論了執行腳本的第一步就是得到一個可用的腳本引擎在完成這項工作之 後就可以利用這個腳本引擎執行相應的腳本了我們可以使用ScriptEngine的eval方法來執行腳本eval方法被重載的多次但最常用的是public Object eval(String script)
下面的例子演示了如何使用eval方法來執行javascript腳本

import javaxscript*;
import javaio*;
import static javalangSystem*;
public class FirstJavaScript
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 得到javascript腳本引擎
  ScriptEngine engine = managergetEngineByName(javascript);
  try
  {
   // 開始運行腳本並返回當前的小時
   Double hour = (Double)engineeval(var date = new Date(); +dategetHours(););
   String msg;
   // 將小時轉換為問候信息
   if (hour < )
   {
    msg = 上午好;
   }
   else if (hour < )
   {
    msg = 下午好;
   }
   else if (hour < )
   {
    msg = 晚上好;
   }
   else
   {
    msg = 晚安;
   }
   outprintf(小時 %s: %s%n hour msg);
  }
  catch (ScriptException e)
  {
   errprintln(e);
  }
 }
}

  上面的例子通過得到當前的小時並將其轉化為問候語上面的程序的輸出信息為

  小時上午好

  這個例子最值得注意的是執行的句腳本最後一句是dategetHours()並未將這個值賦給一個javascript變量這時eval方法就將這樣的值返回這有些類似C語言的(…)運算符如(c=a+b c + d)這個表達式的返回值是a+b+d

  和腳本語言進行交互

  上面例子只是運行了一個非常簡單的腳本這個腳本是孤立的並未通過Java向這腳本傳遞任何的值雖然從這個腳本返回了一個值但這種返回方式是隱式的

  腳本引擎除了這些簡單的功能還為我們提供了更強大的功能甚至可以通過Java向腳本語言中傳遞參數還可以將腳本語言中的變量的值取出來這些功能要依靠ScriptEngine中的兩個方法put和get

  put 有兩個參數一個是腳本變量名另一個是變量的值這個值是Object類型因此可以傳遞任何值
  get 有一個參數就是腳本變量的名

  下面的代碼通過javascript腳本將一個字符串翻轉(這個字符串是通過java傳給javascript的)然後通過java得到這個被翻轉後的字符後然後輸出

   import javaxscript*;
import javaio*;
import static javalangSystem*;
public class ReverseString
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  // 建立javascript腳本引擎
  ScriptEngine engine = managergetEngineByName(javascript);
  try
  {
   // 將變量name和變量值abcdefg傳給javascript腳本
   engineput(name abcdefg);
   // 開始執行腳本
   engineeval(var output = ; +
    for (i = ; i <= namelength; i++) { +
     output = namecharAt(i) + output +
    });
   // 得到output變量的值
   String name = (String)engineget(output);
   outprintf(被翻轉後的字符串%s name);
  }
  catch (ScriptException e)
  {
   errprintln(e);
  }
 }
}

  以上代碼的輸出結果為被翻轉後的字符串gfedcba

  讓腳本運行得更快

  眾所周知解釋運行方式是最慢的運行方式上述的幾個例子無一例外地都是以解釋方式運行的由於Java EE 的腳本引擎可以支持任何實現腳本引擎接口的語言有很多這樣的語言提供了編譯功能也就是說在運行腳本之前要先將這些腳本進行編譯(這裡的編譯一般將不是生成可執行文件而只是在內存中編譯成更容易運行的方式)然後再執行如果某段腳本要運行之交多次的話使用這種方式是非常快的我們可以使用ScriptEngine的compile方法進行編譯並不是所有腳本引擎都支持編譯只有實現了Compilable接口的腳本引擎才可以使用compile進行編譯否則將拋出一個錯誤下面的例子將演示如何使用compile方法編譯並運行javascript腳本

import javaxscript*;
import javaio*;
import static javalangSystem*;
public class CompileScript
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = managergetEngineByName(javascript);
  engineput(counter ); // 向javascript傳遞一個參數
  // 判斷這個腳本引擎是否支持編譯功能
  if (engine instanceof Compilable)
  {
   Compilable compEngine = (Compilable)engine;
   try
   {
    // 進行編譯
    CompiledScript script = pile(function count() { +
      counter = counter +; +
      return counter; +
    }; count(););
    outprintf(Counter: %s%n scripteval());
    outprintf(Counter: %s%n scripteval());
    outprintf(Counter: %s%n scripteval());
   }
   catch (ScriptException e)
   {
    errprintln(e);
   }
  }
  else
  {
   errprintln(這個腳本引擎不支持編譯!);
  }
 }
}
  上面的代碼運行後的顯示信息如下

  Counter:
  Counter:
  Counter:

  在這個例子中先通過compile方法將腳本編譯然後通過eval方法多次進行調用在這段代碼中只有一個函數因此eval就返回了這個函數的值

  動態調用腳本語言的方法

  上面的例子只有一個函數可以通過eval進行調用並將它的值返回但如果腳本中有多個函數或想通過用戶的輸入來決定調用哪個函數這就需要使用invoke方法進行動態調用和編譯一樣腳本引擎必須實現Invocable接口才可以動態調用腳本語言中的方法下面的例子將演示如何通過動態調用的方式來運行上面的翻轉字符串的javascript腳本

import javaxscript*;
import javaio*;
import static javalangSystem*;
public class InvocableTest
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = managergetEngineByName(javascript);
  if (engine instanceof Invocable)
  {
   try
   {
    engineeval(function reverse(name) { +
      var output = ; +
      for (i = ; i <= namelength; i++) { +
       output = namecharAt(i) + output +
        } return output;});
    Invocable invokeEngine = (Invocable)engine;
    Object o = invokeEngineinvoke(reverse name);
    outprintf(翻轉後的字符串%s name);
   }
   catch (NoSuchMethodException e)
   {
    errprintln(e);
   }
   catch (ScriptException e)
   {
    errprintln(e);
   }
  }
  else
  {
   errprintln(這個腳本引擎不支持動態調用);
  }
}

  動態實現接口

  腳本引擎還有一個更吸引的功能那就是動態實現接口如我們要想讓腳本異步地執行即通過多線程來執行那InvokeEngine類必須實現Runnable接口才可以通過Thread啟動多線程因此可以通過getInterface方法來使InvokeEngine動態地實現Runnable接口這樣一般可分為步進行

   使用javascript編寫一個run函數

   engineeval(function run() {print(異步執行);});

   通過getInterface方法實現Runnable接口

   Runnable runner = invokeEnginegetInterface(Runnableclass);

   使用Thread類啟動多線程

   Thread t = new Thread(runner);
tstart();

  下面是實現這個功能的詳細代碼

   import javaxscript*;
import static javalangSystem*;

public class InterfaceTest
{
 public static void main(String args[])
 {
  ScriptEngineManager manager = new ScriptEngineManager();
  ScriptEngine engine = managergetEngineByName(javascript);
  try
  {
   engineeval(function run() {print(異步調用);});
   Invocable invokeEngine = (Invocable)engine;
   Runnable runner = invokeEnginegetInterface(Runnableclass);
   Thread t = new Thread(runner);
   tstart();
   tjoin();
  }
  catch (InterruptedException e)
  {
   errprintln(e);
  }
  catch (ScriptException e)
  {
   Systemerrprintln(e);
  }
 }
}

  其實上面的代碼是通過javascript實現了Runnable接口的run方法


From:http://tw.wingwit.com/Article/program/Java/Javascript/201311/25487.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.