从Python调用Java


123

从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是一个死项目吗?

还有其他选择吗?

问候,大卫


3
您能否详细说明为什么您认为Jython和RPC不适合您的情况?
内森·戴维斯

2
在此期间,似乎有新的JPype版本发布:2011
7

Answers:


51

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

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

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

我已经尝试过Pyjnius / Jnius,JCC,javabridge,Jpype和Py4j。

Py4j有点难以使用,因为您需要启动网关,从而增加了另一层脆弱性。


135

您也可以使用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的方法很好;只是这似乎是一个失败的项目。
David Portabella

8
@alvas如果您的意思是我仍然维护Py4J。
Barthelemy 2014年

@Barthelemy,如果Java代码依赖于库,如何进行集成-在我的情况下为opencv?

1
@stack只需确保在您的类路径中添加opencv,并且在启动GatewayServer时就可以从Python访问它。
Barthelemy

这适用于任何包装吗?我尝试过:s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();在这里,Base64类具有方法encode()和解码(),并且是ch.ethz.ssh2.crypto我的.jar文件中软件包的一部分。我知道了from py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu

19

皮尤尼斯

文件:http : //pyjnius.readthedocs.org/en/latest/

GitHub:https : //github.com/kivy/pyjnius

从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

5

我使用OSX 10.10.2,并成功使用JPype。

遇到Jnius的安装问题(其他人也有),安装了Javabridge,但是在我尝试使用它时出现了神秘的错误,PyJ4的不便之处在于必须首先在Java中启动Gateway服务器,而JCC无法安装。最终,JPype结束了工作。在Github上有一个JPype维护分支。它的主要优点是(a)正确安装,并且(b)可以非常有效地将java数组转换为numpy array(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/…–
Peter

4

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

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

4

最近,我一直在将很多东西集成到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://stackoverflow.com/a/29854281/1977538

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

我已经在Python 2.7上进行过尝试,但是它也应该在3.0上也可以使用。在Windows和Linuxes上均可使用

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


1
呃...你在C#迷失了我。我不会拒绝投票,因为在某些情况下这是可行的方法,但这绝对是假设Windows和许多其他功能。
杰瑞德(Jared)'18

2

我刚刚开始使用JPype 0.5.4.2(2011年7月),并且看起来工作得很好...
我使用的是Xubuntu 10.04


1

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

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


RPC(或REST)对我来说不是一个选择。
David Portabella 2010年

这需要在使用python之前先启动Java进程,并确保它正在运行。这可能是故障点。JPype的方法非常出色;只是这似乎是一个失败的项目。
David Portabella 2010年

我提供一般建议。JNI是一个潜在的雷区。
djna 2010年

0

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

我对问题的解决方案是通过在具有适当包和变量的临时文件中编辑Java代码后,通过从python代码中将beanshell解释程序作为shell commnad调用,将此Java代码作为beanshell脚本运行。

如果我在说什么对您有任何帮助,很高兴能帮助您分享我的解决方案的更多详细信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.