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

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

FunctionObject javascriptFunction = new FunctionObject(/* String*/ javascriptFunctionName, /* Method */ javaMethod, /*Scriptable */ parentScope);

boundScope.put(javascriptFunctionName, boundScope, javascriptFunction);

这里

boundScope

应始终是使功能可用的范围。

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

边界范围

.

但在实例方法中,

parentScope

应为其方法正被绑定的实例。

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

调用函数时,Rhino调用

FunctionObject.call()

传递了对的引用的方法

this

. 如果函数是全局函数,则调用它时不引用

(即

xxx()

而不是

this.xxx()

)的值

传递给

函数对象。调用()

方法是进行调用的范围(在本例中,是

参数将与

scope

参数)。

如果调用的Java方法是一个实例方法,那么这将成为一个问题,因为每个构造函数的JavaDoc都是

FunctionObject

班级:

如果该方法不是静态的,则

值将对应于javascript

价值。任何使用

不是正确的Java类型的值会导致错误。

在上面描述的场景中,情况正是如此。JavaScript

值与Java不对应

值并导致不兼容的对象错误。

解决方案是子类

功能对象

重写

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)的类的实例。

package test;

import org.mozilla.javascript.*;

import java.lang.reflect.Member;

import java.lang.reflect.Method;

//-- This is the class whose instance method will be made available in a JavaScript scope as a global function.

//-- It extends from ScriptableObject because instance methods of only scriptable objects can be directly exposed

//-- in a js scope as a global function.

public class MyScriptable extends ScriptableObject {

public static void main(String args[]) throws Exception {

Context.enter();

try {

//-- Create a top-level scope in which we will execute a simple test script to test if things are working or not.

Scriptable scriptExecutionScope = new ImporterTopLevel(Context.getCurrentContext());

//-- Create an instance of the class whose instance method is to be made available in javascript as a global function.

Scriptable myScriptable = new MyScriptable();

//-- This is not strictly required but it is a good practice to set the parent of all scriptable objects

//-- except in case of a top-level scriptable.

myScriptable.setParentScope(scriptExecutionScope);

//-- Get a reference to the instance method this is to be made available in javascript as a global function.

Method scriptableInstanceMethod = MyScriptable.class.getMethod("myJavaInstanceMethod", new Class[]{Double.class});

//-- Choose a name to be used for invoking the above instance method from within javascript.

String javascriptFunctionName = "myJavascriptGlobalFunction";

//-- Create the FunctionObject that binds the above function name to the instance method.

FunctionObject scriptableInstanceMethodBoundJavascriptFunction = new MyFunctionObject(javascriptFunctionName,

scriptableInstanceMethod, myScriptable);

//-- Make it accessible within the scriptExecutionScope.

scriptExecutionScope.put(javascriptFunctionName, scriptExecutionScope,

scriptableInstanceMethodBoundJavascriptFunction);

//-- Define a simple test script to test if things are working or not.

String testScript = "function simpleJavascriptFunction() {" +

" try {" +

" result = myJavascriptGlobalFunction(12.34);" +

" java.lang.System.out.println(result);" +

" }" +

" catch(e) {" +

" throw e;" +

" }" +

"}" +

"simpleJavascriptFunction();";

//-- Compile the test script.

Script compiledScript = Context.getCurrentContext().compileString(testScript, "My Test Script", 1, null);

//-- Execute the test script.

compiledScript.exec(Context.getCurrentContext(), scriptExecutionScope);

} catch (Exception e) {

throw e;

} finally {

Context.exit();

}

}

public Double myJavaInstanceMethod(Double number) {

return number * 2.0d;

}

@Override

public String getClassName() {

return getClass().getName();

}

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);

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

}

}

}

如果您希望看到修正的行为,请取消对第78行和第79行的注释:

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);

希望这有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值