从 Python 调用 Java

Posted

技术标签:

【中文标题】从 Python 调用 Java【英文标题】:Calling Java from Python 【发布时间】:2011-04-08 19:53:53 【问题描述】:

从 python 调用 java 的最佳方法是什么? (jython 和 RPC 不适合我)。

我听说过 JCC:http://pypi.python.org/pypi/JCC/1.9 用于从 C++/Python 调用 Java 的 C++ 代码生成器 但这需要编译所有可能的调用;我更喜欢另一种解决方案。

我听说过 JPype:http://jpype.sourceforge.net/ 教程:http://www.slideshare.net/onyame/mixing-python-and-java

import jpype 
jpype.startJVM(path to jvm.dll, "-ea") 
javaPackage = jpype.JPackage("JavaPackageName") 
javaClass = javaPackage.JavaClassName 
javaObject = javaClass() 
javaObject.JavaMethodName() 
jpype.shutdownJVM() 

这看起来像我需要的。 但是,最后一个版本是从 2009 年 1 月开始的,我看到有人无法编译 JPype。

JPype 是一个死项目吗?

还有其他选择吗?

【问题讨论】:

您能否详细说明为什么您认为 Jython 和 RPC 不适合您的情况? 看起来在此期间有一个新的 JPype 版本:2011-07-28 上的 0.5.4.2 这是一个边缘题外的问题,部分要求软件推荐,部分还不够清楚(“最佳方式”的确切要求是什么)。也许即使在今天,这个问题仍然可以改进。 【参考方案1】:

您也可以使用Py4J。头版上有一个示例和大量文档,但本质上,您只需从 Python 代码中调用 Java 方法,就好像它们是 Python 方法一样:

from py4j.java_gateway import JavaGateway
gateway = JavaGateway()                        # connect to the JVM
java_object = gateway.jvm.mypackage.MyClass()  # invoke constructor
other_object = java_object.doThat()
other_object.doThis(1,'abc')
gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method

与 Jython 不同,Py4J 的一部分在 Python VM 中运行,因此它始终与最新版本的 Python “保持同步”,您可以使用在 Jython 上运行不佳的库(例如 lxml)。另一部分在您要调用的 Java VM 中运行。

通信是通过套接字而不是 JNI 完成的,Py4J 有自己的协议(优化某些情况,管理内存等)

免责声明:我是 Py4J 的作者

【讨论】:

感谢您的链接。它看起来像是 djna 提出的 CodeMesh 的开源替代方案。我会明确地看看它。但是和CodeMesh有同样的问题,需要先启动Java进程,并确保在使用python之前已经运行(参见项目主网页中的示例,ListPrinter.java -> main -> GatewayServer.start( ))。这是一个可能的故障点。我仍然认为 JPype 的方法非常好;只是它似乎是一个死项目。 @alvas 如果这就是你的意思,我仍然维护 Py4J。 @Barthelemy,如果 Java 代码依赖于库 - 在我的情况下是 opencv,如何进行集成? @stack 只需确保将 opencv 添加到您的类路径中,您就可以在启动 GatewayServer 时从 Python 访问它。 这适用于任何软件包吗?我试过:s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode(); 这里的 Base64 类有方法 encode() 和 decode() 并且是我的 .jar 文件中包 ch.ethz.ssh2.crypto 的一部分。我得到from py4j.reflection import MethodInvoker ImportError: No module named reflection【参考方案2】:

这是我对这个问题的总结:5 种从 Python 调用 Java 的方法

http://baojie.org/blog/2014/06/16/call-java-from-python/(缓存

简短回答:Jpype 工作得很好,并且在许多项目中得到了证明(例如 python-boilerpipe),但是 Pyjnius 比 JPype 更快更简单

我尝试过 Pyjnius/Jnius、JCC、javabridge、Jpype 和 Py4j。

Py4j 有点难用,因为你需要启动一个网关,增加了另一层脆弱性。

【讨论】:

【参考方案3】:

Pyjnius docs 和 Github。

来自 github 页面:

使用 JNI 将 Java 类作为 Python 类访问的 Python 模块。

PyJNIus 是“正在进行中的工作”。

快速概览

>>> from jnius import autoclass
>>> autoclass('java.lang.System').out.println('Hello world') 
Hello world

>>> Stack = autoclass('java.util.Stack')
>>> stack = Stack()
>>> stack.push('hello')
>>> stack.push('world')
>>> print stack.pop()
world
>>> print stack.pop()
hello

【讨论】:

【参考方案4】:

我在 OSX 10.10.2 上,并成功使用了 JPype。

在使用 Jnius (others have too) 时遇到安装问题,Javabridge 已安装,但在我尝试使用时出现了神秘错误,PyJ4 的不便之处在于必须先在 Java 中启动网关服务器,JCC 无法安装。最后,JPype 最终工作了。 Github 上有一个maintained fork of JPype。它的主要优点是 (a) 可以正确安装 (b) 它可以非常有效地将 java 数组转换为 numpy 数组 (np_arr = java_arr[:])

安装过程是:

git clone https://github.com/originell/jpype.git
cd jpype
python setup.py install

你应该可以import jpype

以下演示有效:

import jpype as jp
jp.startJVM(jp.getDefaultJVMPath(), "-ea")
jp.java.lang.System.out.println("hello world")
jp.shutdownJVM() 

当我尝试调用我自己的 java 代码时,我必须先编译 (javac ./blah/HelloWorldJPype.java),并且我必须更改默认的 JVM 路径(否则你会得到莫名其妙的“找不到类”错误)。对我来说,这意味着将 startJVM 命令更改为:

jp.startJVM('/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/MacOS/libjli.dylib', "-ea")
c = jp.JClass('blah.HelloWorldJPype')  
# Where my java class file is in ./blah/HelloWorldJPype.class
...

【讨论】:

一个使 JPype 更易于使用的小包装模块在这里:github.com/petered/spiking-mlp/blob/master/spiking_mlp/…【参考方案5】:

如果您使用的是 Python 3,则有一个名为 JPype1-py3 的 JPype 分支

pip install JPype1-py3

这适用于我在 OSX / Python 3.4.3 上。 (您可能需要export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version

from jpype import *
startJVM(getDefaultJVMPath(), "-ea")
java.lang.System.out.println("hello world")
shutdownJVM()

【讨论】:

【参考方案6】:

我最近将很多东西集成到 Python 中,包括 Java。我发现的最可靠的方法是使用 IKVM 和 C# 包装器。

IKVM 有一个简洁的小应用程序,允许您获取任何 Java JAR,并将其直接转换为 .Net DLL。它只是将 JVM 字节码转换为 CLR 字节码。详情请见http://sourceforge.net/p/ikvm/wiki/Ikvmc/。

转换后的库的行为就像原生 C# 库一样,您可以在不需要 JVM 的情况下使用它。然后,您可以创建一个 C# DLL 包装项目,并添加对转换后的 DLL 的引用。

您现在可以创建一些包装存根来调用您想要公开的方法,并将这些方法标记为 DllEport。详情请见https://***.com/a/29854281/1977538。

包装 DLL 的行为就像原生 C 库一样,导出的方法看起来就像导出的 C 方法。您可以像往常一样使用 ctype 连接到它们。

我已经在 Python 2.7 上尝试过,但它也应该适用于 3.0。适用于 Windows 和 Linux

如果您碰巧使用 C#,那么这可能是在将几乎所有内容集成到 python 时尝试的最佳方法。

【讨论】:

呃...你在 C# 中失去了我。我不会投反对票,因为这在某些情况下是可行的,但这肯定是假设 Windows 和许多其他东西。【参考方案7】:

我刚刚开始使用 JPype 0.5.4.2(2011 年 7 月),它看起来运行良好... 我在 Xubuntu 10.04

【讨论】:

【参考方案8】:

我假设如果您可以从 C++ 转换到 Java,那么您已经准备就绪。我见过你提到的那种产品效果很好。碰巧我们使用的是CodeMesh。我没有特别认可这家供应商,也没有就他们产品的相对质量发表任何声明,但我已经看到它在相当大批量的情况下工作。

我一般会说,如果可能的话,我建议尽量避免通过 JNI 直接集成。一些简单的 REST 服务方法或基于队列的架构往往更易于开发和诊断。如果你仔细使用这种解耦技术,你可以获得相当不错的性能。

【讨论】:

RPC(或 REST)不适合我。 这需要先启动Java进程,并在使用python之前确保它正在运行。这是一个可能的故障点。 JPype 的方法非常好;只是它似乎是一个死项目。 我提供一般建议。 JNI 是一个潜在的雷区。【参考方案9】:

根据我自己尝试在 python 中以类似于 python 代码在 python 中的 java 代码中运行的方式运行一些 java 代码的经验,我无法找到一种简单的方法。

我对我的问题的解决方案是,在使用适当的包和变量编辑临时文件中的 java 代码之后,通过在我的 python 代码中将 BeanShell 解释器作为 shell 命令调用,将这个 java 代码作为 BeanShell 脚本运行。

如果我所谈论的内容对您有任何帮助,我很高兴能帮助您分享我的解决方案的更多细节。

【讨论】:

以上是关于从 Python 调用 Java的主要内容,如果未能解决你的问题,请参考以下文章

C++javapython的一些区别

结束 JavaPython 之战,如何学习所有编程语言?

为大数据软件准备JAVAPython环境

10分钟了解代码命名规范(JavaPython)

为什么全网都在劝你学JavaPython,而不是C++?

牛逼!用 AI 实现 C++JavaPython 代码互译!