一、脚本语言的支持 

    JSR 223中规范了在Java虚拟机上运行的脚本语言与Java程序之间的交互方式。JSR 233是JavaSE6的一部分,在Java表中API中的包是javax.script。目前Java虚拟机支持比较多的脚本语言,比较流行的有JavaScript、Scala、JRuby、Jython和Groovy等。 

1. 脚本引擎 
    Java中执行脚本需要脚本语言对应的脚本引擎,JSR 223定义了脚本引擎的注册和查找机制。JavaSE6中自带了JavaScript语言的脚本引擎,基于Mozilla的Rhino实现,可以通过三种方式查找脚本引擎: 
    ① 通过脚本名称获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");

② 通过文件扩展名获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");

③ 通过MIME类型来获取:

  1. ScriptEngine engine = new ScriptEngineManager().getEngineByMimeType("text/javascript");

如下代码,查找注册JavaScript脚本引擎,打印"Hello!",JavaScript脚本中的println是Rhino引擎额外提供的方法。 

  1. public class BasicScripting {
  2. public void greet() throws ScriptException {
  3. ScriptEngineManager manager = new ScriptEngineManager();
  4. ScriptEngine engine = manager.getEngineByName("JavaScript");
  5. //ScriptEngine engine = manager.getEngineByExtension("js");
  6. //ScriptEngine engine = manager.getEngineByMimeType("text/javascript");
  7. if (engine == null) {
  8. throw new RuntimeException("找不到JavaScript语言执行引擎。");
  9. }
  10. engine.eval("println('Hello!');");
  11. }
  12. public static void main(String[] args) {
  13. try {
  14. new BasicScripting().greet();
  15. } catch (ScriptException ex) {
  16. Logger.getLogger(BasicScripting.class.getName()).log(Level.SEVERE, null, ex);
  17. }
  18. }
  19. }

2. 语言绑定 
   脚本语言支持API使用语言绑定对象实现Java语言编写的程序与脚本语言间的数据传递。语言绑定对象实际上就是一个简单的哈希表,用来存放和获取需要共享的数据,其定义的接口为javax.script.Bindings,继承自java.util.Map接口。一个脚本引擎在执行过程中可能会使用多个语言绑定对象,不同语言绑定对象的作用域不同。ScriptEngine类提供out和get方法对脚本引擎中特定作用域的默认语言绑定对象进行操作。 

使用默认的语言绑定对象: 

  1. public void useDefaultBinding() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. engine.put("name", "Alex");
  4. engine.eval("var message = 'Hello, ' + name;");
  5. engine.eval("println(message);");
  6. Object obj = engine.get("message");
  7. System.out.println(obj);
  8. }

亦可以自定义语言绑定对象(如语言绑定对象中包含程序自己独有的数据等情形……): 

  1. public void useCustomBinding() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. Bindings bindings = new SimpleBindings();
  4. bindings.put("hobby", "playing games");
  5. engine.eval("println('I like ' + hobby);", bindings);
  6. }

3. 脚本执行的上下文 
    脚本引擎通过执行过程中的上下文对象获取与脚本执行相关的信息,同时允许程序员通过此对象配置脚本引擎的行为。其上下文对象来自javax.script.ScriptContext接口,类似于J2EE中javax.servlet.ServletContext接口,该接口主要包含3类信息: 

① 输入输出 
    默认情况下,脚本输入输出都是在标准控制台中,可以通过setReader和setWriter方法对输出流进行重定向,可以通过setErrorWriter方法进行错误输出重定向。 

  1. //例:将输出重定向到文件
  2. public void scriptToFile() throws IOException, ScriptException {
  3. ScriptEngine engine = getJavaScriptEngine();
  4. ScriptContext context = engine.getContext();
  5. context.setWriter(new FileWriter("output.txt"));
  6. engine.eval("println('Hello World!');");
  7. }

② 自定义属性 
    上下文中通过setAttribute和getAttribute方法获取和设置属性,类似于ServletContext中设置和获取属性操作。与ServletContext中不同的是,ScriptContext中的属性是有作用域之分的,ScriptContext按不同的顺序在不同的作用域中进行属性查找(类似于JSP中EL表达式属性的作用域)。通过ScriptContext的getScopes可以得到其中所有可用的作用域,其中预定义了两个作用域:常量ScriptContext.ENGINE_SCOPE(当前的脚本引擎)和ScriptContext.GLOBAL_SCOPE(从同一引擎工厂中创建的所有脚本引擎对象)。 

  1. public void scriptContextAttribute() {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
  5. context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
  6. context.getAttribute("name"); //值为Bob
  7. }

③ 语言绑定对象 
    语言绑定对象位于ScriptContext中,同样也有作用域之分,范围越小,优先级越高。执行如下代码,输出的name值为Bob。 

  1. public void scriptContextBindings() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. Bindings bindings1 = engine.createBindings();
  5. bindings1.put("name", "Alex");
  6. context.setBindings(bindings1, ScriptContext.GLOBAL_SCOPE);
  7. Bindings bindings2 = engine.createBindings();
  8. bindings2.put("name", "Bob");
  9. context.setBindings(bindings2, ScriptContext.ENGINE_SCOPE);
  10. engine.eval("println(name);");    //Bob
  11. }

也可以通过ScriptContext获取语言绑定对象: 

  1. public void useScriptContextValues() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
  5. bindings.put("name", "Alex");
  6. engine.eval("println(name);");
  7. }

前面说到语言绑定对象存在于上下文环境中,故context中保存的自定义属性其实也是保存于语言绑定对象中的,如2中的语言绑定。 

  1. public void attributeInBindings() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. ScriptContext context = engine.getContext();
  4. context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
  5. engine.eval("println(name);");
  6. }

4. 脚本编译 
    脚本语言一般均是解释执行的,相对于编译执行的语言,效率较低一些。当脚本语言需要多次重复执行时,可以先对煎熬本进行编译,避免重复解析,提高效率(注:脚本编译需要脚本引擎支持,实现javax.script.Compilable接口)。JavaSE中自带的JavaScript引擎是支持对脚本进行编译的,编译的脚本用javax.script.CompiledScript来表示。 

  1. public class ScriptCompile extends JsScriptRunner {
  2. //对脚本进行编译
  3. public CompiledScript compile(String scriptText) throws ScriptException {
  4. ScriptEngine engine = getJavaScriptEngine();
  5. if (engine instanceof Compilable) {
  6. CompiledScript script = ((Compilable) engine).compile(scriptText);
  7. return script;
  8. }
  9. return null;
  10. }
  11. //先编译再执行
  12. public void run(String scriptText) throws ScriptException {
  13. CompiledScript script = compile(scriptText);
  14. if (script == null) {
  15. return;
  16. }
  17. for (int i = 0; i < 100; i++) {
  18. script.eval();
  19. }
  20. }
  21. public static void main(String[] args) {
  22. ScriptCompile sc = new ScriptCompile();
  23. try {
  24. sc.run("println('Hello');");
  25. } catch (ScriptException ex) {
  26. Logger.getLogger(ScriptCompile.class.getName()).log(Level.SEVERE, null, ex);
  27. }
  28. }
  29. }

5. 方法调用 
    Java虚拟机支持脚本的意义在于实现函数式的编程,即脚本中最重要的便是方法。一些脚本引擎允许使用者单独调用脚本中的某个方法,支持此操作的脚本引擎可以通过实现javax.script.Invocable接口,支持顶层方法或者某对象中成员方法的调用。使用方法调用时最好先检查脚本引擎是否实现了Invocable接口,JavaSE中的JavaScript引擎已实现了Invocable接口。 

① 在Java中调用脚本中的顶层方法 

  1. public void invokeFunction() throws ScriptException, NoSuchMethodException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "function greet(name) { println('Hello, ' + name); } ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. invocable.invokeFunction("greet", "Alex");
  7. }

② 调用脚本中某对象的成员方法 

  1. public void invokeMethod() throws ScriptException, NoSuchMethodException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "var obj = { getGreeting : function(name) { return 'Hello, ' + name; } }; ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. Object scope = engine.get("obj");
  7. Object result = invocable.invokeMethod(scope, "getGreeting", "Alex");   //第一个参数为方法所属对象
  8. System.out.println(result);
  9. }

③ 指定脚本中的方法为Java接口的实现 
    Greet是Java实现的接口,包含一个方法getGreeting,通过Invocable.getInterface()方法指定脚本中的方法为Java接口的实现。 

  1. public void useInterface() throws ScriptException {
  2. ScriptEngine engine = getJavaScriptEngine();
  3. String scriptText = "function getGreeting(name) { return 'Hello, ' + name; } ";
  4. engine.eval(scriptText);
  5. Invocable invocable = (Invocable) engine;
  6. Greet greet = invocable.getInterface(Greet.class);
  7. System.out.println(greet.getGreeting("Alex"));
  8. }

Java语言的动态性支持的更多相关文章

  1. 《深入理解Java 7核心技术与最佳实践》读书笔记(2) Java语言动态性引言

    Java语言是一种静态类型的编程语言.静态类型的含义是指在编译时进行类型检查.Java源代码中的每个变量的类型都要显式地进行声明.所有变量.方法的参数和方法返回值的类型在程序运行之前就必须是已知的.J ...

  2. [原]Java修炼 之 基础篇(一)Java语言特性

    学习软件开发,首先要选择的就是选择需要采用的编程语言,考虑语言本身的优缺点和实际需求,综合评价之后选择相关的语言进行系统开发.本篇博客开始就从近年来比较流行的Java开始为大家讲起. 背景 1995年 ...

  3. Java语言概述

    1.1 基础知识 ·第一代语言 打孔机--纯机器语言 ·第二代语言 汇编 ·第三代语言 C.Pascal.Fortran面向过程的语言 C++面向过程/面向对象 Java跨平台的纯面向对象的语言 .N ...

  4. Java语言国际化

    事实上,Java语言不可能支持所有国家和语言,如需要获取Java语言所支持的语言和国家,可调用Locale类的getAvailableLocale方法获取,该方法返回一个Locale数组,该数组里包含 ...

  5. java语言与jvm虚拟机简介

    一.java语言 1.1 支持面向对象编程oop 强调支持,因为java同样可以面向过程编程. oop的三大特性是:封装.继承.多态. 封装主要针对成员变量而言,oop的思想要求成员变量均为私有,不应 ...

  6. 第1章 Java语言概述--HelloWorld--环境搭建

    SE学什么 第1章 Java语言概述 第2章 基本语法 第3章 数组 第4章 面向对象编程(上) 第5章 面向对象编程(中) 第6章 面向对象编程(下) 第7章 异常处理 第8章 枚举类&注解 ...

  7. Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar

    Spring Cloud Netflix多语言/非java语言支持之Spring Cloud Sidecar 前言 公司有一个调研要做,调研如何将Python语言提供的服务纳入到Spring Clou ...

  8. JDK1.7新特性(3):java语言动态性之脚本语言API

    简要描述:其实在jdk1.6中就引入了支持脚本语言的API.这使得java能够很轻松的调用其他脚本语言.具体API的使用参考下面的代码: package com.rampage.jdk7.chapte ...

  9. Java语言支持的变量类型有哪几种

    Java语言支持的变量类型有: 类变量:独立于方法之外的变量,用 static 修饰. 实例变量:独立于方法之外的变量,不过没有 static 修饰. 局部变量:类的方法中的变量. 实例: publi ...

  10. Java语言支持的变量类型有

    Java语言支持的变量类型有: 类变量:独立于方法之外的变量,用 static 修饰. 实例变量:独立于方法之外的变量,不过没有 static 修饰. 局部变量:类的方法中的变量.

随机推荐

  1. manim边学边做--带箭头直线

    带箭头的直线就是有方向的直线,既可以用来表示矢量,也可以用来标记某个关键位置.manim中提供了4种常用的带箭头的直线模块: Arrow:单箭头的直线 DoubleArrow:双箭头的直线 Label ...

  2. 苹果(ios)打包证书下载

    这里,首先需要明确的是,苹果打包证书不能共用,因此证书下载是只能下载自己的证书,不是去下载别人的证书. 那么自己的证书又是如何生成的呢?去什么地方下载呢?第一次开发ios的同学们,肯定会问这个问题. ...

  3. [OI] Kruskal 重构树

    算法介绍 Kruskal 重构树用于快速判断节点的连通性. 考虑到,假如两个节点是联通的,则他们之间总会有一条边被选入最小生成树内,因此他们在最小生成树内也是联通的. 也就是说,我们可以通过求最小生成 ...

  4. CSP2024-S 游记

    9-21 今天考完了初赛,明显感觉数学门槛变高了一些,有高中数学知识才能保证看得懂题意,只是苦了小学和初中同学,看数据参加人数还涨了50%,权当拉低分数线了吧.用小图灵估分70.应该是稳过.

  5. linux中透明巨页与巨页的区别

    在Linux中,透明巨页(Transparent HugePage)和巨页(HugePage)是两种不同的内存管理技术. 透明巨页是Linux内核中的一项特性,旨在提高内存的利用率和性能.它通过将内存 ...

  6. ADO.NET 连接数据库 【vs2022 + sqlServer】

    using System.Data; using System.Data.SqlClient; namespace Zhu.ADO.NET { internal class Program { pri ...

  7. 洛谷P1381单词背诵

    单词背诵 题目描述 灵梦有 \(n\) 个单词想要背,但她想通过一篇文章中的一段来记住这些单词. 文章由 \(m\) 个单词构成,她想在文章中找出连续的一段,其中包含最多的她想要背的单词(重复的只算一 ...

  8. Module Warning (from ./node_modules/postcss-loader/dist/cjs.js): Warning

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  9. linux 基础(1)快速查询指令的用法

    --help 几乎所有的指令,都可以使用--help选项进行查询.给命令使用--help选项,就会直接出现一段说明命令的文字. > date --help 用法:date [选项]... [+格 ...

  10. synchronized的四种锁状态

    Java 多线程的锁都是基于对象的,Java 中的每一个对象都可以作为一个锁. 类锁,其实就是 Class 对象的锁. Class 对象是一种特殊的 Java 对象,代表了程序中的类和接口.Java ...