将Java Integer绑定到JavaScriptEngine;不起作用
Binding a Java Integer to JavaScriptEngine doesn't work
为了了解将Java对象绑定到动态语言中的符号是如何工作的,我编写了以下尖峰测试,将java.lang.Integer
绑定到要在JavaScript中更改的符号i
:
@Test
public void bindToLocalVariable() throws ScriptException {
javax.script.ScriptEngineManager sem
= new javax.script.ScriptEngineManager();
javax.script.ScriptEngine engine
= sem.getEngineByName("JavaScript");
Integer i = new Integer(17);
engine.put( "i", i );
engine.eval( "i++;" ); // Now execute JavaScript
assertEquals( 18, i.intValue() );
}
不幸的是,我失败了。
java.lang.AssertionError: expected:<18> but was:<17>
JavaScript知道符号i
(否则它会抛出一个ScriptException
,但事实并非如此),但增量操作i++
不会对原始Integer
对象执行。
有什么解释吗?
我不知道JavaSrciptEngine,但Integer
是不可变的,因此在JavaScript中更改它后,您仍然会有以前的值。
编辑:删除自动装箱以使其更加清晰:
它很像这样:
Integer i = new Integer(17);
Integer j = i; //should be similar to the assignment in Javascript
j++; //the change to j is not reflected in i
System.out.println(i); //prints 17 not 18
以下是代码中发生的情况:
Integer i = new Integer(17);
这行创建了两个东西:
Integer
类型的局部变量,名称为i
- 值为
17
的新Integer
对象
使用对新创建的Integer
对象的引用来初始化局部变量(即,它现在指向Integer
对象)。
Integer
对象不能被修改,因为它是不可变的
局部变量可以通过为其分配新的引用来修改。
engine.put( "i", i );
此行将i
的值(它是对Integer
对象的引用)传递给方法put()
。这意味着put
只有知道Integer
对象,而不知道变量i
。由于Integer
对象本身无法修改,因此该方法(或任何其他方法)无法影响存储在局部变量i
中的内容。
engine.eval( "i++;" ); // Now execute JavaScript
此方法有效地操纵了前一行创建的JavaScript变量i
。该变量被用本地Java变量i
的值初始化,但它与本地变量不同。
assertEquals( 18, i.intValue() );
在这里检查本地Java变量i
的值,它是不变的。使断言正确的唯一方法是将其他东西分配给i
(例如i = new Integer(18)
)。
感谢Thomas和Joachim Sauer指出问题是由java.lang.Integer
的不变性引起的。
整数通过engine.put()
映射到一个真正的JavaScript变量,可以像数字一样处理。如果需要结果,请调用engine.get()
将其传递回Java。这与上的List<String>
示例不同http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/其中Java对象被传递到脚本,其自己的方法(如Java中定义的)通过回调到Java并使用反射从脚本中应用到它。
一个有趣的细节是,Integer
将从JavaScript中检索为Double
,这表明确实存在到JavaScript数据对象的前向和后向映射。
这是通过的测试(省略了engine
的实例化,它仍然与我的问题中的相同——我在此期间提取了它)。
@Test
public void bindToInteger() throws ScriptException {
Integer i = 17;
engine.put( "i", i );
engine.eval( "i++" ); // Execute JavaScript
// i is mapped back to java.lang.Double by get()
double f = (Double) engine.get("i");
assertEquals( 18, (int) f );
}
- 没有找到相关文章