将Java整数绑定到JavaScriptEngine不会';行不通

将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对象绑定到符号的工作原理,我编写了以下代码,将
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 );        

    }