JDK1.7新特性(3):java语言动态性之脚本语言API
时间:2022-05-04
本文章向大家介绍JDK1.7新特性(3):java语言动态性之脚本语言API,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
简要描述:其实在jdk1.6中就引入了支持脚本语言的API。这使得java能够很轻松的调用其他脚本语言。具体API的使用参考下面的代码:
1 package com.rampage.jdk7.chapter2;
2
3 import java.io.FileWriter;
4 import java.io.IOException;
5
6 import javax.script.Bindings;
7 import javax.script.Compilable;
8 import javax.script.CompiledScript;
9 import javax.script.Invocable;
10 import javax.script.ScriptContext;
11 import javax.script.ScriptEngine;
12 import javax.script.ScriptEngineManager;
13 import javax.script.ScriptException;
14 import javax.script.SimpleBindings;
15
16 /**
17 * 简单的脚本引擎使用方法
18 *
19 * @author zyq
20 *
21 */
22 public class SimpleScriptAPI {
23 public static void main(String[] args) throws ScriptException, IOException, NoSuchMethodException {
24 SimpleScriptAPI simpleScriptEngine = new SimpleScriptAPI();
25
26 // Part 1: 通用的脚本引擎用法
27 ScriptEngine engine = simpleScriptEngine.getJavaScriptEngine();
28 if (engine == null) {
29 throw new RuntimeException("找不到JavaScript脚本执行引擎!");
30 }
31 engine.eval("var a = 12;");
32
33 // Part 2: 不同脚本语言与java之间的对象绑定
34 engine.put("name", "Alex");
35 engine.eval("var message = 'hello ' + name");
36 Object message = engine.get("message");
37 System.out.println(message); // hello Alex
38
39 // 当然也可以通过SimpleBinds对象来进行变量绑定或者通过脚本引擎的createBindings方法
40 Bindings bindings = new SimpleBindings();
41 bindings = engine.createBindings();
42 bindings.put("hobby1", "java");
43 bindings.put("hobby2", "dota");
44 engine.eval("var message2 = 'I like ' + hobby1 + ' and ' + hobby2", bindings);
45 // 使用binding来绑定的变量只能在脚本语言内部是使用,java语言内获取不到对应的变量
46 System.out.println(engine.get("message2")); // null
47 System.out.println(engine.get("hobby1")); // null
48 System.out.println(engine.get("hobby2")); // null
49 engine.put("hobby1", "java");
50 engine.put("hobby2", "dota");
51 engine.eval("var message2 = 'I like ' + hobby1 + ' and ' + hobby2");
52 System.out.println(engine.get("message2")); // I like java and dota
53 System.out.println(engine.get("hobby1")); // java
54 System.out.println(engine.get("hobby2")); // dota
55
56 // Part 3: 脚本执行上下文
57 // ScriptContext的setReader/setWriter/setErrorWriter可以分别设置脚本执行时候的输入来源,输出目的地和错误输出目的地
58 ScriptContext context = engine.getContext();
59 context.setWriter(new FileWriter("output.txt"));
60 engine.eval("var a = 13");
61 // ScriptContext中也有setAttribute和getAttribute方法来自定义属性。属性有不同的作用域之分。
62 // 每个作用域都以一个对应的整数表示其查找顺序,该整数越小,说明查找时的顺序更优先。
63 // 因此在设置属性时需显示的指定所在的作用域,在获取属性的时候可以指定查找的作用域。也可以选择根据作用域优先级
64 // 自动进行查找。
65 // 但是脚本执行上下文所能包含的作用域可以通过 getScopes 方法得到而不能随意指定
66 System.out.println(context.getScopes()); // [100, 200]
67 // ScriptContext预先定义了两个作用域: ENGINE_SCOPE(当前脚本引擎) 和 GLOBAL_SCOPE(从同一引擎工厂创建出来的所有脚本引擎),前者的优先级更高
68 context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE);
69 context.setAttribute("name", "Bob", ScriptContext.ENGINE_SCOPE);
70 System.out.println(context.getAttribute("name")); // Bob
71 // ScriptContext的setbindings方法设置的语言绑定对象会影响到ScriptEngine在执行脚本时的变量解析。
72 // ScriptEngine的put和get方法所操作的实际上就是ScriptContext中作用域为ENGINE_SCOPE的语言绑定对象。
73 // 从ScriptContext中得到语言绑定对象之后,可以直接对这个对象进行操作。如果在ScriptEngine的eval中没有
74 // 指明所使用的语言绑定对象,实际上起作用的是ScriptContext中作用域为ENGINE_SCOPE的语言绑定对象。
75 Bindings binding1 = engine.createBindings();
76 binding1.put("name", "Alex");
77 context.setBindings(binding1, ScriptContext.GLOBAL_SCOPE);
78 Bindings binding2 = engine.createBindings();
79 binding2.put("name", "Bob2");
80 context.setBindings(binding2, ScriptContext.ENGINE_SCOPE);
81 System.out.println(engine.get("name")); // Bob2
82 Bindings binding3 = context.getBindings(ScriptContext.ENGINE_SCOPE);
83 binding3.put("name", "Alex2");
84 System.out.println(engine.get("name")); // Alex2
85 context.setAttribute("name", "Bob3", ScriptContext.ENGINE_SCOPE);
86 System.out.println(engine.get("name")); // Bob3
87
88 // Part 4: 脚本的编译
89 // 脚本语言一般是解释执行的,脚本引擎在运行时需要先解析脚本之后再执行。一般来说
90 // 通过解释执行的方式运行脚本的速度比先编译再运行会慢一些。所以对于需要多次执行的脚本,我们
91 // 可以选择先编译,以防止重复解析。不是所有的脚本语言都支持对脚本进行编译,如果脚本支持
92 // 编译,他会实现 javax.script.Compilable接口。编译的结果用CompiledScript来表示。
93 if (engine instanceof Compilable) {
94 CompiledScript script = ((Compilable) engine).compile("var a = 12; b = a * 3;");
95 script.eval();
96 }
97
98 // Part 5: 方法调用
99 // 有些脚本引擎允许使用者单独调用脚本中的某个方法。支持这种调用方法的脚本引擎可以实现
100 // javax.script.Invocable 接口。通过Invocable接口既可以调用脚本中的顶层方法,也可一
101 // 调用对象中的成员方法。如果脚本中的顶层方法或者对象中的成员方法实现了java中的接口,
102 // 可以通过Invocable接口中的方法来获取及脚本中对应的java接口 的实现对象。这样就可以
103 // 在java中定义借口,在脚本中实现接口。程序中使用该接口的其他部分代码并不知道接口是
104 // 由脚本来实现的。
105 String scriptText = "function greet(name) {return 'hello ' + name; }";
106 engine.eval(scriptText);
107 Invocable invocable = (Invocable) engine;
108 System.out.println(invocable.invokeFunction("greet", "Alex")); // hello Alex
109 // 如果调用的是脚本中对象的成员方法,则需要用invokeMethod.
110 scriptText = "var obj = {getGreeting: function(name) {return 'hello ' + name;}};";
111 engine.eval(scriptText);
112 Object scope = engine.get("obj");
113 System.out.println(invocable.invokeMethod(scope, "getGreeting", "Bob")); // hello Bob
114 // 在脚本中实现接口
115 scriptText = "function getGreeting(name) {return 'Hello ' + name;}";
116 engine.eval(scriptText);
117 Greet greet = invocable.getInterface(Greet.class); // 接口必须是public类型的
118 System.out.println(greet.getGreeting("KiDe"));
119 }
120
121 private ScriptEngine getJavaScriptEngine() {
122 ScriptEngineManager manager = new ScriptEngineManager();
123 // PS: 通过脚本引擎管理者来获取对应引擎,有三种方法:一是通过getEngineByName(这时只能是 javascript 或者
124 // JavaScript)
125 ScriptEngine engine = manager.getEngineByName("JavaScript");
126 // 第二种方法是通过 getEngineByExtension (这时候只能是全小写的js)
127 // engine = manager.getEngineByExtension("js");
128 // 第三种方法是通过 getEngineByMimeType (这时候也必须是全小写的 text/javascript)
129 // engine = manager.getEngineByMimeType("text/javascript");
130
131 return engine;
132 }
133 }
1 package com.rampage.jdk7.chapter2;
2
3 public interface Greet {
4 String getGreeting(String name);
5 }
- 无人驾驶系列——深度学习笔记:Tensorflow的安装-windows系统
- 2018年12大顶级云安全威胁
- 缤果盒子为域名意识打call 六位数秒下bingobox.com
- 用Qt写软件系列二:QCookieViewer(浏览器Cookie查看器)
- 用Qt写软件系列一:QCacheViewer(浏览器缓存查看器)
- 用Qt写软件系列三:一个简单的系统工具(上)
- ChartDirector应用笔记(三)
- 汇编语言 手记9
- 程序员一年写百万行代码是什么体验?这肯定是个Bug
- ChartDirector应用笔记(二)
- ChartDirector应用笔记(一)
- DB Cache
- oracle多用户并发及事务处理
- 数据中心整合会导致更高的云价格吗?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 服务发现之consul的介绍、部署和使用
- Mybatis处理查询map 为null 导致查询map无该key对象
- 深入对比TOML,JSON和YAML
- consul配置参数大全、详解、总结
- 跳跃表原理和实现
- 你动、蒙娜丽莎跟着一起动,OpenCV这么用,表情口型造假更难防了
- 好用的PHP高性能多并发restful的HTTP Client
- Golang程序调试工具介绍(gdb vs dlv)
- tcp_tw_reuse、tcp_tw_recycle注意事项
- PHP性能规范
- PHP代码规范
- php调试利器之phpdbg
- 【DB笔试面试860】在Oracle中,如何判断Oracle是32位还是64位?
- JsonPath实践(四)
- Python代码转Latex公式,这个开源库用一行代码帮你搞定