java的脚本机制
脚本API可以让你在Java平台上运行脚本语言(js,ruby等等)
ScriptEngineManager类 | 效果 |
---|---|
getEngineByName(语言名称) | 通过名称返回ScriptEngine实例 |
getEngineByExtension(扩展名) | 通过扩展名返回ScriptEngine实例 |
getEngineByMimeType(MIME类型) | 通过MIME返回ScriptEngine实例 |
getEngineFactories() | 返回List<ScriptEngineFactory>工厂集合 |
createBindings() | 实例化Bindings对象 |
ScriptEngineFactory类 | 效果 |
---|---|
getNames() | 返回该工厂知道的名字的集合 |
getExtensions() | 返回该工厂知道的扩展名的集合 |
getMimeTypes() | 返回该工厂知道的MIME类型的集合 |
你可向ScriptEngineFactory询问该工厂支持的引擎名
ScriptEngineManager manager=new ScriptEngineManager();
List<ScriptEngineFactory> list=manager.getEngineFactories();
ScriptEngineFactory factory=list.get(0);
for(String i:factory.getNames()) {
System.out.println(i);
}//这段程序的目的是输出第一个工厂支持的名字
一旦你有了引擎后你就可以像这样调用脚本(本文都以js代码做示范):
ScriptEngineManager manager=new ScriptEngineManager();
ScriptEngine engine=manager.getEngineByName("js");//得到js引擎
engine.eval("print(\"这是脚本语言输出的\")");//运行js代码
ScriptEngine类 | 效果 |
---|---|
eval(脚本语言代码) | 可以通过String或者通过Reader类从文件里读入代码来执行,也会返回一个Object值 |
eval(脚本语言代码,bindings对象) | 同上,但指定一个Bindings |
put(变量名,值) | 绑定一个变量的值 |
get(“变量名”) | 得到一个变量的值 |
getContext() | 返回Context对象 |
可以在一个引擎上调用多个脚本,如下所示,我们先定义一个变量,再进行计算,得到返回值
engine.eval("n=66");//定义n变量
Object num=engine.eval("n+1");返回n+1的值
System.out.print(num);
我们也可以这样绑定变量(变量值可以是java对象):
engine.put("n",66);//绑定n变量
Object num=engine.eval("n+1");返回n+1的值
System.out.print(num);
作用域
除了引擎作用域,任何添加到ScriptEngineManager的绑定对所有引擎可见(即全局作用域)。
除了这些外,还可以将变量绑定到Bindings对象中,然后将其传到eval中:
Bindings b=engine.createBindings();//实例化Bindings
b.put("n", 66);
Object num=engine.eval("n+1",b);
System.out.print(num);//输出67
BIndings类 | |
---|---|
put(变量名,值) | 绑定变量 |
get(变量名) | 得到变量 |
重定向输入输出
可以重定向脚本的标准输入输出。如js里的print和println,其他的输出不管
Writer pw=new PrintWriter("D:1.txt","UTF-8");//指定输出位置和编码格式
engine.getContext().setWriter(pw);
engine.eval("print(\"啦啦啦\")");//打印在1.txt文件里
Context类 | 效果 |
---|---|
getReader()和setReader(Reader) | 得到或设置 脚本的标准输入 位置 |
getWriter()和setWriter(Reader) | 得到或设置 脚本的标准输出 位置 |
getErrorWriter()和setErrorWriter(Reader) | 得到或设置 脚本的标准错误输出 位置 |
调用脚本的函数和方法
我们可以调用脚本语言里的函数。提供这些功能的脚本引擎要实现 Invocable接口,如js脚本引擎。
ScriptEngine engine=new ScriptEngineManager().getEngineByName("JavaScript");
//在js里定义一个p函数
engine.eval("function p(str){return 'hello '+str+'!'}");
//获得一个Invocable接口的对象
Invocable invocable=(Invocable)engine;
Object result=invocable.invokeFunction("p","shit");//调用js的函数
System.out.print(result);
如果脚本语言是面向对象的,那还可以调用 对象里的方法
//在js中定义Girl类
engine.eval("function Girl(str){this.jk=str}");
engine.eval("Girl.prototype.f1="+"function(str){return this.jk+str}");
//实例化girl对象
Object girl=engine.eval("new Girl(\"jk美少女\")");
//调用girl对象里的f1方法
Object result=((Invocable)engine).invokeMethod(girl,"f1","是我");
System.out.print(result);//输出结果为jk美少女是我
Invocable接口 | 效果 |
---|---|
invokeFunction(方法名,参数......) | 调用 脚本的函数 |
invokeMethod(对象,方法名,参数.....) | 调用 脚本对象的方法 |
getInterface(Class对象) | 返回指定的类的对象 |
在js中,如果定义了相同名字的函数,那么可以通过这个接口来调用它。相当于得到了实现了这个接口的一个对象
public interface Hello{
String hello(String str);
}//这是在Java里编写的Hello接口
//————————————————————————————————————
//在js里实现Hello接口
engine.eval("function hello(str){return str+\",hello\"}");
Hello h=((Invocable)engine).getInterface(Hello.class);
System.out.print(h.hello("wrold"));
编译脚本
某些时候处于效率考虑,会先把脚本代码编译为中间格式,再来使用:
CompiledScript script=((Compilable)engine).compile("print(123)");
script.eval();
Compilable接口 | |
---|---|
compile(字符串代码) | 返回编译了的CompiledScript对象 |
compile(Reader对象) | 同上 |
CompiledScript类 | |
---|---|
eval() | 执行编译好了的代码 |
eval(Bindings对象) | 同上,但加上Bindings对象里的变量 |