将 Java Integer 绑定到 JavaScriptEngine 不起作用
为了了解如何将 Java 对象绑定到动态语言中的符号,我编写了以下 spike 测试,将 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 对象。
有什么解释吗?
To see how binding Java objects to symbols in a dynamic language works, I wrote the following spike test, binding a java.lang.Integer
to the symbol i
to be changed in JavaScript:
@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() );
}
Unfortunately, I get a failure.
java.lang.AssertionError: expected:<18> but was:<17>
JavaScript knows the symbol i
(otherwise it would have thrown a ScriptException
which is not the case), but the increment operation i++
is not performed on the original Integer
object.
Any explanations?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我不知道 JavaSrciptEngine,但
Integer
是不可变的,因此在 JavaScript 中更改它后您仍然拥有以前的值。编辑:删除自动装箱以使其更清晰:
它很像这样:
I don't know JavaSrciptEngine but
Integer
is immutable, thus you'd still have the previous value after changing it i JavaScript.Edit: removing autoboxing to make it more clear:
It's much like this:
以下是您的代码中发生的情况:
此行创建了两件事:
i
的Integer
类型的局部变量。Integer
对象,其值为17
。局部变量通过对新创建的
Integer
对象的引用进行初始化(即它现在指向Integer
对象)。Integer
对象无法修改,因为它是不可变的。局部变量可以通过分配新的引用来修改。
此行将
i
的值(这是对Integer
对象的引用)传递给方法put()
。这意味着put
仅知道Integer
对象,而不知道变量我
。而且由于Integer
对象本身无法修改,因此该方法(或任何其他方法)无法影响本地变量我。
此方法有效地操作了前面一行创建的 JavaScript 变量
i
。该变量是用本地 Java 变量i
的值初始化的,但是它与该本地变量不同。这里检查本地 Java 变量
i
的值,该值没有变化。使该断言正确的唯一方法是将其他内容分配给i
(例如i = new Integer(18)
)。Here's what's happening in your code:
This line creates two things:
Integer
with the namei
.Integer
object with the value17
.The local variable is initialized with a reference to the newly created
Integer
object (i.e. it points to theInteger
object now).The
Integer
object can't be modified, since it's immutable.The local variable could be modified by assigning a new reference to it.
This line passes the value of
i
(which is the reference to theInteger
object) to the methodput()
. This means thatput
only knows of theInteger
object and not of the variablei
. And since theInteger
object itself can't be modified, there is no way for the method (or any other method) to influence what is stored in the local variablei
.This method effectively manipulates the JavaScript variable
i
created by the line before. That variable was initialized with the value of the local Java variablei
, but it is not the same as that local variable.Here you check the value of the local Java variable
i
, which is unchanged. The only way you could make that assert correct is by assigning something else toi
(e.g.i = new Integer(18)
).感谢 Thomas 和 Joachim Sauer 指出问题是由于
java.lang.Integer
的不变性造成的。该整数通过
engine.put()
映射到真正的 JavaScript 变量,并且可以像数字一样对待。如果您需要结果,请调用engine.get()
将其传回 Java。这与 上的List
示例不同http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/,其中 Java 对象被传递给脚本,它自己的方法(如定义在 Java 中) 通过回调到 Java,使用反射从脚本内应用到它。一个有趣的细节是,
Integer
将从 JavaScript 中检索为Double
,这表明确实存在到 JavaScript 数据对象的前向和后向映射。这是通过的测试(省略了
engine
的实例化,它仍然与我的问题中的相同 - 我同时提取了它)。Thanks to Thomas and Joachim Sauer for pointing out that the problem was due to the immutability of
java.lang.Integer
.The integer is mapped to a genuine JavaScript variable by
engine.put()
and can be treated like a number. If you need the result, callengine.get()
to pass it back into Java. This is different to theList<String>
example on http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ where a Java object is passed to the script, and its own methods (as defined in Java) are applied to it from within the script by callback to Java, using reflection.It is an interesting detail that the
Integer
will be retrieved asDouble
from JavaScript, indicating that there really was a forward and backward mapping to a JavaScript data object.Here is the passing test (leaving out the instantiation of
engine
which is still the same as in my question - I have extracted it in the meantime).