Java调用Python

本文详细介绍了如何通过Cython、C和JNI实现在Java中调用Python代码的过程,涉及Python、Java、C++的混合编程,包括Python的C接口、Cython的使用、Java Native Interface(JNI)的应用,以及多模块调用的注意事项。通过这个实例,读者可以了解到多种语言间的交互方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说句题外话:无论是在C中还是Java中调用Python,当遇到多线程的时候一定要想到GIL锁的存在。

在Python中调用C/C++代码:这也是最常见的混合编程方式。并且有很多优秀的开源项目可以帮助我们实现这种场景,比如pybind11.

在C/C++中调用Python代码:Python也为这种场景提供了丰富的接口。

Java中调用C/C++:也可以通过JNI实现Java与C/C++的相互调用。

那么Python和Java之间是否能够实现相互调用呢?

不难得到肯定的答案,至少可以通过Python->C/C++->Java的方式实现。

如果你了解Cython这个神器,就可以知道从Python到C是十分简单的。然后再到Java也就不是问题了。虽然想到了这个思路,但是为了更快的达到目的,试验之前还是在网上找了下,果然找到一篇十分不错的文章:

Python一键转Jar包,Java调用Python新姿势! - 掘金 (juejin.cn)

但在过程中还是遇到了一些细节问题,在这篇文章的基础上整理了下面的内容。

一、Java代码,文件名Test.java

这一块儿和文档中介绍的稍有不同。新建一个java工程,将这个文件加到里面去。

先把Java代码放上看起来有点本末倒置,但是后面会发现,在写接下来的C代码时会用到这个工程,来生成对应的C接口名。

package solution.src;

public class Test {
    static {
        System.load("/home/yourpath/python_C_Java/python/Test.cpython-36m-x86_64-linux-gnu.so");
    }

    public native void initModule();
    public native void uninitModule();
    public native String testFunction(String param);

    public static void main(String[] args) {
        Test tester = new Test();
        tester.initModule();
        String result = tester.testFunction("this is called from java");
        tester.uninitModule();
        System.out.println(result);
    }
}

二、Python文件,取名JavaTest.pyx(pyx时cython代码的后缀,python是cython的一个子集,因此里面的代码完全可以写成python)

我们的目的就是让这些接口在Java中发挥它的作用,但这还不是在Java中直接调用的接口。这里照搬文章中的代码,但里面Python_API_TestFunction的函数名,之前是JNI_API_testFunction。在我的环境里面这个函数名字无论如何都找不到,后来自己写了个更简单的测试函数,测试成功。再后来又把我自己定义的函数删掉,改回JNI_API_testFunction又可以了,现在想应该是在网上拷贝代码时格式的问题。但这里还是用修改后的名字吧,因为JNI_这种格式在一些情况下是有固定含义的。总之运行时若提示找不到函数,则先怀疑一下Python代码本身是否有问题。

# FileName: Test.py
# 示例代码:将输入的字符串转变为大写
def logic(param):
  print('this is a logic function')
  print('param is [%s]' % param)
  return param.upper()

# 接口函数,导出给Java Native的接口
def Python_API_TestFunction(param):
  print("enter JNI_API_test_function")
  result = logic(param)
  print(result)
  return res
<think>好的,用户想了解如何在Java调用Python脚本或函数,特别是通过subprocess或JEP库的示例代码。首先,我需要回忆相关的Java调用Python的方法。常见的有使用Runtime执行命令行、ProcessBuilder、Jython、JEP等。用户提到了subprocess和JEP,所以重点在这两个方法。 首先,subprocess应该是Java的ProcessBuilder或Runtime.exec来启动Python进程。这里需要给出示例代码,展示如何执行Python脚本并获取输出。注意异常处理和流的读取,避免阻塞。 然后是JEP,这是一个允许在Java中嵌入Python解释器的库。需要说明如何配置JEP的依赖,比如Maven或Gradle,然后编写调用Python函数的示例代码。要强调JEP的性能优势,特别是在需要频繁调用的场景下。 另外,用户提供的引用中有提到JPype,但用户问题里没有明确提到,是否需要简要比较一下?不过用户明确问了subprocess和JEP,所以可能不需要深入其他方法,但可以稍微提一下其他选项作为扩展。 需要检查引用中的信息是否相关。引用1提到了JPype,但用户可能更关注JEP和subprocess,所以引用可以作为补充说明其他方法存在,但主要回答用户提到的两个方法。引用2是关于JDBC漏洞利用的文件,似乎不相关,可能不需要引用。 接下来,按照用户的结构要求,回答需要分点,结构清晰,使用中文,行内公式用$...$,独立公式单独成段。不过用户的问题不涉及数学公式,所以可能不需要使用。但需要生成相关问题。 最后,确保示例代码正确,语法高亮,并解释每个步骤。注意subprocess方法中的输入输出流处理,避免死锁。同时,JEP的示例需要展示如何传递参数和获取返回值。 总结步骤:先介绍subprocess方法,给出代码示例和注意事项;然后介绍JEP方法,配置依赖和示例代码;最后比较两种方法的优缺点,适用场景。生成相关问题时要围绕Java调用Python的其他方法、异常处理、性能优化等。</think>### Java调用Python脚本或函数的方法教程 #### 1. 使用 `ProcessBuilder`(命令行调用) 通过Java启动子进程执行Python脚本,适用于简单脚本调用。 ```java import java.io.BufferedReader; import java.io.InputStreamReader; public class PythonSubprocess { public static void main(String[] args) { try { ProcessBuilder pb = new ProcessBuilder("python", "script.py", "arg1", "arg2"); Process process = pb.start(); // 读取Python脚本输出 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println("Python输出: " + line); } // 等待进程结束 int exitCode = process.waitFor(); System.out.println("Python脚本退出码: " + exitCode); } catch (Exception e) { e.printStackTrace(); } } } ``` **注意事项**: - 需保证Python环境变量已配置。 - 通过参数传递数据时需注意字符串转义。 - 若脚本执行时间较长,建议异步处理以避免阻塞主线程。 --- #### 2. 使用 **JEP**(Java Embedded Python) JEP提供直接嵌入Python解释器的能力,支持高效交互[^1]。 **步骤1:添加依赖(Maven)** ```xml <dependency> <groupId>black.ninia</groupId> <artifactId>jep</artifactId> <version>4.0.3</version> </dependency> ``` **步骤2:调用Python函数** ```java import jep.Jep; import jep.JepConfig; public class JepExample { public static void main(String[] args) { try (Jep jep = new Jep()) { // 执行Python代码 jep.eval("def add(a, b): return a + b"); // 调用Python函数 jep.eval("result = add(3,5)"); Object result = jep.getValue("result"); System.out.println("计算结果: " + result); // 输出8 } catch (JepException e) { e.printStackTrace(); } } } ``` **优势**: - 支持直接传递Java对象到Python环境(需类型转换)。 - 避免频繁启动进程的开销,适合高性能场景。 --- #### 3. 方法对比 | 方法 | 适用场景 | 性能 | 复杂度 | |---------------|--------------------------|-------|--------| | ProcessBuilder| 简单脚本调用 | 较低 | 低 | | JEP | 高频调用/复杂交互 | 高 | 中 | | JPype | 从Python调用Java(反向) | 中 | 高 | ---
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值