Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/363.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/416.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从JavaScript调用Java实例的方法?_Java_Javascript_Rhino_Method Call - Fatal编程技术网

如何从JavaScript调用Java实例的方法?

如何从JavaScript调用Java实例的方法?,java,javascript,rhino,method-call,Java,Javascript,Rhino,Method Call,我正在使用Mozilla Rhino JavaScript模拟器。它允许我将Java方法添加到上下文中,然后像调用JavaScript函数一样调用它们。但我不能让它工作,除非我使用静态方法 问题在于文档的这一部分: 如果该方法不是静态的,Java“this”值将对应于JavaScript“this”值。任何试图使用不正确Java类型的“this”值调用函数的行为都会导致错误 显然,我的Java“this”值与JavaScript中的值不一致,我不知道如何使它们一致。最后,我想用Java创建一个实

我正在使用Mozilla Rhino JavaScript模拟器。它允许我将Java方法添加到上下文中,然后像调用JavaScript函数一样调用它们。但我不能让它工作,除非我使用静态方法

问题在于文档的这一部分:

如果该方法不是静态的,Java“this”值将对应于JavaScript“this”值。任何试图使用不正确Java类型的“this”值调用函数的行为都会导致错误

显然,我的Java“this”值与JavaScript中的值不一致,我不知道如何使它们一致。最后,我想用Java创建一个实例,并在全局范围内安装几个方法,这样我就可以从Java初始化实例,但在脚本中使用它


有人对此有一些示例代码吗?

您可以做的是将Java实例绑定到Javascript上下文,然后从Javascript中,该标识符将是对“真实”Java对象的引用。然后,您可以使用它从Javascript向Java进行方法调用

Java方面:

    final Bindings bindings = engine.createBindings();
    bindings.put("javaObject", new YourJavaClass());
    engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Javascript:

    javaObject.methodName("something", "something");
现在,该示例假设您正在使用JDK 6 java.util.script API在java和Rhino之间切换。和“普通”犀牛有点不同,但基本思想是一样的

或者,您可以将Java类导入到Javascript环境中,当您对Java类的引用使用Javascript“new”时,Rhino会为您提供对Java对象的Javascript域引用。

当使用Java方法时(无论是静态的还是非静态的)将在我们使用以下逻辑的范围内作为全局函数提供:

FunctionObject javascriptFunction = new FunctionObject(/* String*/ javascriptFunctionName, /* Method */ javaMethod, /*Scriptable */ parentScope);
boundScope.put(javascriptFunctionName, boundScope, javascriptFunction);
在这里,
boundScope
应该始终是函数可用的范围

然而,父作用域的值取决于我们是绑定实例方法还是静态方法。对于静态方法,它可以是任何有意义的范围。它甚至可以与
boundScope
相同

但是在实例方法的情况下,
parentScope
应该是其方法被绑定的实例

以上只是背景信息。现在我将解释问题所在,并给出一个自然的解决方案,即允许直接作为全局函数调用实例方法,而不是显式创建对象实例,然后使用该实例调用方法

调用函数时,Rhino调用
FunctionObject.call()
方法,该方法传递了对
this
的引用。如果函数是一个全局函数,则调用该函数时不引用
this
(即
xxx()
而不是
this.xxx()
),传递给
FunctionObject.call()
方法的
this
变量的值就是进行调用的范围(即,在这种情况下,
参数的值将与
范围
参数的值相同)

如果调用的java方法是一个实例方法,这将成为一个问题,因为根据
FunctionObject
类的构造函数的JavaDocs:

如果该方法不是静态的,Java
this
值将对应于JavaScript
this
值。任何试图使用不正确Java类型的
this
值调用函数的行为都将导致错误

在上面描述的场景中,情况正是如此。javascript
this
值与java
this
值不对应,并导致不兼容的对象错误

解决方案是子类化
FunctionObject
,重写
call()
方法,强制“修复”该
引用,然后让调用正常进行

比如:

FunctionObject javascriptFunction = new MyFunctionObject(javascriptFunctionName, javaMethod, parentScope);
boundScope.put(javascriptFunctionName, boundScope, javascriptFunction);


private static class MyFunctionObject extends FunctionObject {

    private MyFunctionObject(String name, Member methodOrConstructor, Scriptable parentScope) {
      super(name, methodOrConstructor, parentScope);
    }

    @Override
    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
      return super.call(cx, scope, getParentScope(), args);
    }
  }
我认为最好通过下面粘贴的一个自包含/完整的示例来理解它。在这个示例中,我们将实例方法myJavaInstanceMethod(双倍数字)公开为javascript范围(“scriptExecutionScope”)内的一个全局函数。因此,在这种情况下,“parentScope”参数的值必须是包含此方法的类的实例(即MyScriptable)

如果要查看修复程序的行为,请取消注释第78行和注释第79行:

return super.call(cx, scope, getParentScope(), args);
//return super.call(cx, scope, thisObj, args);
//return super.call(cx, scope, getParentScope(), args);
return super.call(cx, scope, thisObj, args);
如果要查看没有修复的行为,请注释第78行和取消注释第79行:

return super.call(cx, scope, getParentScope(), args);
//return super.call(cx, scope, thisObj, args);
//return super.call(cx, scope, getParentScope(), args);
return super.call(cx, scope, thisObj, args);

希望这能有所帮助。

@Jawad的答案很好,但它仍然要求parentScope是您试图插入的对象的父对象。如果您想将全局函数添加到使用initStandardObjects()创建的作用域中,您必须使用共享作用域(这有点解释了,但缺少完整的示例)

以下是我是如何做到的(这是Android,请原谅Kotlin):


谢谢,这很有效。因为我直接使用Rhino API,所以代码是:
global.defineProperty(“javaObject”,javaObject,ScriptableObject.CONST);
(虽然我不确定
CONST
,但其他属性应用更少)。如果我想使用像[[1,3]、[4,5]、[6,9]这样的多维整数数组调用函数那么我如何传递对象[]作为params?如何从Java实例中获得可用的
parentScope
?我已经用一个完整的示例更新了答案。希望有帮助。谢谢。作为一个比以前更好的答案,我想这意味着我不能把
Java.lang.String
的实例放在脚本的上下文中。我总是要把它包装起来扩展了
FunctionObject
。感谢@Jawad给出了这个美妙的答案。你救了我一天。两周后我就完成了。脱帽致敬