静态性:编译时进行类型检查,所有变量、方法的参数和返回值的类型子程序运行之前必须是已知的。
动态性:运行时进行类型检查,源代码中无需显示声明类型。
脚本语言支持API
脚本的执行需要由该脚本语言对应的脚本引擎,Java程序可以选择同时包含多种脚本语言的执行引擎
1、获取引擎
Java6自带了基于Mozilla的Rhino实现的JS脚本引擎。
ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); if( engine == null ){ throw new RuntimeException("找不到JavaScription引擎") } engine.eval("println('Hello!')");
可以按照三种方式获得引擎:
manager.getEngineByName("JavaScriptiono")manager.getEngineByExtension("js")
manager.getEngineByMineType("text/javascript")
2、语言绑定
ScriptEngine engine = getJavaScriptEngine(); engine.put("name","Alex");//绑定到ScriptContext.ENGINE_SCOPE engine.eval("var message = ' hello, ' + name;") Object obj = engine.get("message"); System.out.println(obj);
Bindings bindings = new SimpleBindings();//自定义绑定对象,也可以通过 engine.createBindings创建。 bindings.put("hobby","playing games");// engine.eval("println('I like ' + hobby);", bindings);//仅在当前eval调用生效。
注:
3、脚本上下文
javax.script.ScriptContext
定义输入输出,setReader,setWriter,setErrorWriter.
ScriptContext = engine.getContext(); context.setWriter(new FileWrite("output.txt")); engine.eval("println('Hello world!');");
setAttribute和getAttribute设置属性,属性有作用域
ScriptionContext.getScopes();方法获得所有作用域,作用域用整数表示,数字越小越优先。作用域固定不能自定义。
预定义2个作用域:ScriptContext.GLOBAL_SCOPE 和 ScriptContext.ENGINE_SCOPE
ScriptContext context = engine.getContext(); context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE); context.setAttribute("name","Bob",ScriptContext.ENGINE_SCOPE); context.getAttribute("name"); // Bob
绑定的对象,与作用域相对应
Bindings b1 = engine.createBindings(); Bindings b2 = engine.createBindings(); b1.put("name", "Alex") b2.put("name","Bob") context.setBindings( b1, ScriptContext.GLOBAL_SCOPE); context.setBindings( b2, ScriptContext.ENGINE_SCOPE); engine.eval("println(name);"); // Bob
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE); bindgings.put("name", "Alex");//获取了语言绑定对象后,直接对这个对象操作 engine.eval("println(name);"); // Alex
context.setAttribute("name", "Alex", ScriptContext.GLOBAL_SCOPE); engine.eval("println(name);")// Alex,直接使用sc的setAttribute,同样可见。
多需要多次执行的脚本进行编辑,加快执行速度
如果脚本引擎实现javax.script.Compilable接口,即可支持。
public CompiledScript compile(String scriptText) throws ScriptException{ ScriptEngine engine = getJavaScriptEngine(); if(engine instanceof Compilable){ //不是所有脚本都实现此接口,所以要判断。 CompiledScript script = ((Compilable) engine).compile(scriptText); return script;//编译后的结果为javax.script.CompiledScript } return null; } public void run(String scriptText) throws ScritException{ CompiledScript script = compile(scriptText); if(script == null){ return; } for(int i=0; i<100; i++){ script.eval();//调用CompiledScript的eval }// CompileScript的eval方法与ScriptEngine的eval相同。 }
脚本引擎实现javax.script.Invocable接口
Invocable的invokeFunction来调用脚本中的顶层方法。
String scriptText = "function greet(name) { printn('Hello, ' + name } ; "; engine.eval(scriptText); Invocable invocable = (Invocable) engine; invocable.invokeFunction("greet","Alex";
String scriptText = "var obj = { getGreeting:function(name){ return 'Hello, ' + name; } }; "; engine.eval(scriptText); Invocable invocable = (Invocable)engine; Object scope = engine.get("obj"); Object result = invocable.invokeMethod(scope, "getGreeting", "Alex");//调用传入对象。 System.out.println(result);invokeMethod与invokeFunction区别在于,前者需要制定包含待调用方法的对象。
String scriptText = "function getGreeting(name){ return 'Hello, ' + name; } "; engine.eval(scriptText); Invocable invocable = (Invocable) engine; Greet greet = invocable.getInterface(Greet.class);//Greet是Java定义的接口 System.out.println(greet.getGreeting("Alex")); //getGreeting是定义的方法。这里的接口的实现是 脚本中的 顶层方法来完成
也可以由脚本中的对象的成员方法来实现, getInterface 另一种重载形式可以接受一个额外的参数来指定接口实现所在的对象。
脚本语言使用场景。
1、在Java里新建一个bindings对象,是一个 js的 obj,
比如 config = {};
Bindings b1 = new SimpleBindings;
engine.eval( "config = {}", b1);
2、输入修改信息, 通过命令行或输入框等
var scriptText = "config.windowsWidth = 300;"
3、java获得修改信息,直接丢给js引擎,
engine.eval( scriptText , b1);
4、java程序通过读取这个 config 对象,获取更新后的信息。
这样就完成了, java 借助 js,完成对变量的自由设置,大大减少代码量。