将Java整数绑定到JavaScriptEngine不会';行不通
为了了解在动态语言中将Java对象绑定到符号的工作原理,我编写了以下代码,将将Java整数绑定到JavaScriptEngine不会';行不通,java,javascript,rhino,Java,Javascript,Rhino,为了了解在动态语言中将Java对象绑定到符号的工作原理,我编写了以下代码,将Java.lang.Integer绑定到要在JavaScript中更改的符号I: @Test public void bindToLocalVariable() throws ScriptException { javax.script.ScriptEngineManager sem = new javax.script.ScriptEngineManager(); javax
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>
java.lang.AssertionError:应为:但为:
JavaScript知道符号i
(否则它会抛出ScriptException
,情况并非如此),但增量操作i++
不会对原始整数
对象执行
有什么解释吗?我不知道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
的值(它是对整数
对象的引用)传递给方法put()
。这意味着put
只有知道Integer
对象,而不知道变量i
。由于整数
对象本身无法修改,因此该方法(或任何其他方法)无法影响存储在局部变量i
中的内容
engine.eval( "i++;" ); // Now execute JavaScript
此方法有效地处理由前一行创建的JavaScript变量i
。该变量是用本地Java变量i
的值初始化的,但是它与该本地变量不同
assertEquals( 18, i.intValue() );
这里检查本地Java变量i
的值,该值保持不变。唯一能使断言正确的方法是给i
赋值(例如i=newinteger(18)
)。感谢Thomas和Joachim Sauer指出问题是由于java.lang.Integer
的不变性造成的
整数通过engine.put()
映射到一个真正的JavaScript变量,可以像数字一样处理。如果需要结果,请调用engine.get()
将其传递回Java。这与列表
示例不同,在该示例中,Java对象被传递到脚本,其自己的方法(如Java中定义的)通过回调Java(使用反射)从脚本内部应用到脚本
一个有趣的细节是,Integer
将作为Double
从JavaScript中检索,这表明确实存在到JavaScript数据对象的正向和反向映射
这里是通过测试(省略了引擎的实例化,它仍然与我的问题中的相同-我同时提取了它)
@杰斯珀,你说得对。我不应该在这里抛出自动装箱:)我忘了自动装箱也会将赋值添加到新的整数对象中。使用engine.get(“I”)
在计算“I++;”
后,获取引擎中I
的值。记住,现在有两个东西叫做i
:在Java
应用程序中的本地Integer
变量和JavaScript引擎中的变量。一个来自Java,一个来自JavaScript的引用。@rplantiko:不,那是错误的。你甚至发现事实并非如此。JavaScript引擎无法更改i
的值(而且它也无法更改存储在Integer
对象中的值,因为Integer
是不可变的)。至于整数的不变性,我希望在幕后自动装箱,就像Java语句I++代码>这也改变了i的值。约阿希姆:但是谢谢你评论的要点。我不知道JS不是在原版上工作,而是在复制。
@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 );
}