【问题标题】:How can I implement a generic interface in Rhino JS?如何在 Rhino JS 中实现通用接口?
【发布时间】:2014-03-13 23:16:07
【问题描述】:

我有一个包含通用接口的应用程序:

public interface IMyInterface<T> {
    public int calcStuff(T input); 
}

我可以清楚地用 Java 实现这一点:

public class Implementor implements IMyInterface<FooObject>{
    public int calcStuff(FooObject input){ ... }
}

我找到了一个关于在 Rhino 中实现 Java 非泛型接口的教程,并且可以验证它在我的上下文中是否有效。

据我了解,由于动态类型系统等因素,Javascript没有泛型,所以Rhino在其JS解析器中没有提供这样的让步。任何做研究的尝试都会让我得到大量关于 Rhino mocks 泛型接口而不是 Rhino JS 泛型接口实现的结果。

【问题讨论】:

  • 你能澄清一下它在什么意义上不起作用吗?当你提供一个实现时,犀牛会抱怨吗?据我了解,JS 中的任何接口都是通用的(或键入Object)所以我想知道您要完成什么。
  • @oberhamsi 它不起作用,因为我找不到任何类型的对语法的引用来引用 Rhino JavaScript 中的泛型类。这是否意味着使用calcStuff(FooObject obj) 创建接口会隐式返回IMyInterface&lt;FooObject&gt; 实现?
  • 无论calcStuff() 看起来如何,它的行为都会像IMyInterface&lt;Object&gt;。我不知道这是否是幕后实际发生的事情,但如果我在 rhino 中实现 java.util.Map 它接受任何东西,即行为类似于java.util.Map&lt;Object, Object&gt;

标签: java oop generics interface rhino


【解决方案1】:

从少数 Javascript 的角度来看,没有泛型,没有接口,甚至没有类。在 Javascript 中,您有 Objects with functions that may be created from prototypes

在 Javascript 中“实现”一个 Java 接口仅意味着提供一些 Javascript 对象,该对象具有与接口方法名称相同的函数名称,并且这些函数具有与相应接口方法相同数量的参数。

所以要实现你提供的通用示例接口,你可以这样写:

myGenericInterfaceImpl = new Object();
// Generic type is supposed to be <String> int calcStuff(String)
myGenericInterfaceImpl.calcStuff = function(input) { 
        println("--- calcStuff called ---");
        println("input" + input);
        println("typeof(input):" + typeof(input));

        // do something with the String input
        println(input.charAt(0));
        return input.length();
    }

这里假设预期的泛型类是String 类型。

现在假设你有一个 Java 类,它接受这个具有通用 String 类型的接口:

public static class MyClass {
    public static void callMyInterface(IMyInterface<String> myInterface){
        System.out.println(myInterface.calcStuff("some Input"));
    }
}

然后你可以像这样从 Javascript 调用这个方法:

// do some Java thing with the generic String type interface
Packages.myPackage.MyClass.callMyInterface(new Packages.myPackage.IMyInterface(myInterfaceImpl)));

关于该主题的一些背景信息

如果您对 Rhino 的幕后工作感兴趣,在 Javascript 中实现 Java 接口时,我建议您查看以下 Rhino 类:

本质上,静态方法InterfaceAdapter#create() 将调用VMBridge#newInterfaceProxy(),它为接口返回一个Java Proxy,它使用InterfaceAdapter 的实例来处理接口上的方法调用。此代理会将接口上的任何 Java 方法调用映射到相应的 Javascript 函数。

 **
 * Make glue object implementing interface cl that will
 * call the supplied JS function when called.
 * Only interfaces were all methods have the same signature is supported.
 *
 * @return The glue object or null if <tt>cl</tt> is not interface or
 *         has methods with different signatures.
 */
static Object create(Context cx, Class<?> cl, ScriptableObject object)

当我第一次在 Java 和 Javascript 中使用通用接口时,通过逐步调试我在创建的 Rhino 代理上的调用(但你当然需要 Rhino 源要做到这一点,并且设置它可能有点麻烦)。

另外请注意,Java Scripting API 使用的默认 Rhino 实现不允许实现多个 Java 接口或扩展 Java 类。来自Java Scripting Programmer's Guide

Rhino 的 JavaAdapter 已被覆盖。 JavaAdapter 是由 哪些 Java 类可以被 JavaScript 和 Java 接口扩展 由 JavaScript 实现。我们已经替换了 Rhino 的 JavaAdapter 使用我们自己的 JavaAdapter 实现。在我们的实施中, JavaScript 对象只能实现单个 Java 接口。

因此,如果您需要这些功能,则无论如何都需要安装原始的 Rhino 实现(这样更容易设置源代码)。

【讨论】:

  • 谢谢。我正在使用非JDK(原始)Rhino。我是否正确理解,由于 Javascript 具有动态类型系统,我只会在第一次调用时收到类型错误(例如,如果我尝试将 HashMap 传递给接口实现)而不是在我实际上将接口传递给了一些库函数,这些函数可能会在运行时存储它一段时间?
  • @hexafraction 如果您将错误的类型传递给接口,您根本不会收到任何类型错误。如果您尝试访问在调用接口时不存在的函数(表示 Java 方法),您将在 Javascript 中收到错误。但实际上也是如此,如果您在 Java 中实现接口,而忽略泛型。如果您实际上将参数转换为错误的类型,那么您只会收到类型错误 - 泛型类型在运行时被删除。因此,您可以将 Javascript 接口视为一个简单的 Java 接口,它忽略了泛型类型。
  • 这非常有帮助,非常感谢。我想我可以找到一个应用程序级别的解决方法(坦率地说,动态类型让实现者在这种情况下更加灵活)
猜你喜欢
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多