这是一个很好的问题.一般来说,语言互操作有几种方法:
>在完全独立的,独立的程序/进程中运行代码,并使用进程间通信(IPC)或其他网络协议(在TCP之上构建的TCP或更高级别协议,如HTTP,通常使用REST-ful API或某种形式的RPC) system)在用不同语言编写的两个进程之间发送信息.
>将一种语言“透明化”到另一种语言中(例如,使用JSweet或TeaVM转换器将Java代码转换为JavaScript代码),然后使用一种语言从原始代码创建单个应用程序/进程以及另一种语言的转换代码language(现在与最终应用程序中构建的其他代码使用相同的语言).
>使用通用中间语言和低级“本机”接口,允许代码进行互操作.大多数语言都与C进行某种形式的互操作(因为C是大多数操作系统支持的共同标准).虽然这不适用于客户端JavaScript(虽然一些原则仍然与Native Client(NaCL)相关),但使用NodeJs,您可以使用node-gyp和cwrap调用C代码.一旦你在C land,你可以使用Java Native Interface (JNI)调用Java(尽管可以通过让SWIG为您自动生成大部分样板,而不是直接写入JNI规范,更容易实现使用JNI从C调用Java代码).
与所有事情一样,对各种方法进行权衡:
>方法#1:
>优点:
>相对直截了当
>适用于几乎所有编程语言
>每个子系统与另一个子系统完全隔离
>每个系统都可以用语言习惯的方式进行调试
>缺点:
>必须定义共享协议
>可能导致冗余的重复代码
>协议必须保持同步
>更改必须向后兼容或者会中断
>注意:protocol buffers可以帮助解决这个问题
>序列化/反序列化开销
> channel可以增加其他开销(例如,如果通过Internet进行通信,而不是通过UNIX域套接字在同一台机器上进行通信)
>必须考虑通信机制的安全性
>子系统之间的数据加密
>端点的访问控制
>方法#2:
>优点:
>没有序列化/反序列化开销
>可以使用目标语言的惯用语来调试最终系统
>缺点:
>并非所有语言都可以从一个语言转换到另一个语言
>即使转换器支持这两种语言:
>通常只支持该语言的一个子集
>可能需要修改/修改代码以允许它进行转换
>可能需要修复/修改转换器
>翻译中稍微不同的语义可能导致微妙的,令人惊讶的错误
>子系统之间没有隔离
>方法#3:
>优点:
>没有序列化/反序列化开销
>比方法#2更多的支持
>无需用任何一种语言重写原始代码
>缺点:
>必须成为SWIG等深奥工具的专家
>结果很难调试
> NodeJS代码的stacktraces突然包含C,JVM和Java代码
>调试工具不容易跨越语言(例如,可能最终通过JVM代码解释Java,而不是单步执行实际的Java代码)
>对象的所有权,跨语言的垃圾收集可能导致令人惊讶/难以处理错误,如果所有权语义未正确编码
>语言之间的不同线程模型或语言之间的其他语义不匹配会使整个系统错误/难以调试
使用方法#1和方法#3的系统(以及使用方法#2的系统听证会),我强烈建议尽可能使用方法#1;只有当你发现序列化开销难以维持(并且你无法优化通信协议/机制来处理这个问题)时,我才会冒险进入其他领域.话虽如此,如果语言非常相似(如从TypeScript到JavaScript的转换),方法#2可以成功,如果使用这种机制的范围非常有限(例如只需暴露一个),方法#3就可以成功这种方式很小但经常被称为/性能敏感的功能).