Java调用Python协同开发的方式

本文介绍了Java如何与Python进行协同开发,包括使用命令行、推荐的Jython方式以及高级的JNI接口。详细讲解了环境配置、Python安装和通过Java调用Python的方法,重点介绍了ProcessBuilder和Runtime.getRuntime().exec()的使用,以及Jython作为中间桥梁的便利性。
摘要由CSDN通过智能技术生成

Java调用Python协同开发的方式

背景

Java与Python结合开发是指将Python语言与Java语言结合起来,利用它们的优势,共同开发一个应用程序。
Python语言拥有许多强大的特性,如易于学习、快速开发、可扩展性等,而Java语言则拥有跨平台、可靠性、安全性等优势,因此将它们结合起来,可以发挥出更大的作用。
在一个大型企业系统中,Java可能用于后端服务和业务逻辑,而Python可能用于数据分析和机器学习任务。在这种情况下,两种语言需要能够协同工作,以实现全面的功能。

环境准备

操作系统:Win11

Java开发环境:安装并配置了Java开发环境,包括Java Development Kit (JDK) 和设置了正确的环境变量。(这里就不详细讲JDK的安装了,可以参考 最详细jdk安装以及配置环境(保姆级教程)

Python解释器:安装Python解释器,并且可以在命令行中执行python命令。可以通过在命令行中输入python --version来验证Python是否正确安装。

下面开始下载安装Python、配置环境变量。

下载、安装Python解释器

下载Python
  • 下载地址
    https://www.python.org/getit/
  • 选择Windows版本,我这里下载的最新的
    (最好选择Python3.x,因为Python2.x官方已经不再维护了)
    在这里插入图片描述
安装Python
  • 点击Python解释器(python-3.12.1-amd64.exe)运行
  • 勾选[Add python.exe to PATH],添加到Python到环境变量中,我这里选择的Customize installation自定义安装。
    在这里插入图片描述
  • 直接点击【next】下一步。
    在这里插入图片描述
  • 选择为所有用户安装,配置自定义安装路径,这里我安装在D盘,点击Install
    在这里插入图片描述
  • 安装完成
    在这里插入图片描述
  • 检查Python解释器环境变量是否配置成功
    右键[此电脑] -> 点击[属性] -> 进入[高级系统设置] -> 选择[环境变量]

在这里插入图片描述在这里插入图片描述

  • 查看系统变量Path(如果安装的时候没有选择添加到环境变量,则可以自行添加到此处)

在这里插入图片描述

  • cmd运行,检查版本号
python --version

在这里插入图片描述

调用方法

系统需要有Python解释器环境。

一、使用命令行调用(较原始)

1.使用ProcessBuilder类调用Python

Java提供了ProcessBuilder类,可以在Java代码中调用外部程序或脚本。我们可以利用这个类调用Python解释器,从而执行Python的代码。通过使用ProcessBuilder类,我们可以传递命令行参数,获取脚本的输出结果,并实现Java与Python的互操作性。

  • Java内执行命令代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PythonTest {

    public static void main(String[] args) {
        try {
            // 创建ProcessBuilder对象,指定要执行的命令和参数
            ProcessBuilder pb = new ProcessBuilder("python", "-c", "print('Hello, Python!')");
            // 启动子进程并等待其完成
            Process process = pb.start();

            // 读取子进程的输出结果
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待子进程完成并获取退出值
            int exitCode = process.waitFor();
            System.out.println("Exit Code: " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

}
2.使用Runtime.getRuntime().exec()调用
  • 准备Python的测试文件 test.py
def say_hello(name):
    return 'Hello, ' + name + '!'

if __name__ == '__main__':
    print(say_hello('Python'))
  • Java调用
public static void main(String[] args) {
    try {
        // 创建ProcessBuilder对象,指定要执行的命令和参数
        ProcessBuilder pb = new ProcessBuilder("python", getResourceFilePath("test.py"));
        // 启动子进程并等待其完成
        Process process = pb.start();

        // 读取子进程的输出结果
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }

        // 等待子进程完成并获取退出值
        int exitCode = process.waitFor();
        System.out.println("Exit Code: " + exitCode);
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

/**
 * 获取资源文件路径
 *  * @param fileName 文件名称
 * @return 文件绝对路径
 */
public static String getResourceFilePath(String fileName) {
    // 获取当前项目的根目录路径
    String rootPath = System.getProperty("user.dir");

    // 拼接资源文件夹的相对路径
    String resourceFolderPath = rootPath + File.separator + "src" + File.separator + "test" + File.separator + "resources" + File.separator + fileName;

    // 创建File对象,并打印资源文件夹的绝对路径
    File resourceFolder = new File(resourceFolderPath);

    // 打印资源文件夹的绝对路径
    return resourceFolder.getAbsolutePath();
}

二、使用Jython(推荐)

Jython 是一个将Python代码嵌入到Java中的工具,它使Java应用程序能够调用和执行Python代码。这为Java开发人员提供了在其应用程序中集成Python脚本的能力。

在maven坐标中添加:

<dependency>
    <groupId>org.python</groupId>
    <artifactId>jython-standalone</artifactId>
    <version>2.7.2</version>
</dependency>

编写Java代码测试:

public static void main(String[] args) {
    PythonInterpreter interpreter = new PythonInterpreter();
    interpreter.exec("print('Hello from Python!')");
}

运行结果:
在这里插入图片描述

三、使用JNI(Java Native Interface)(难度较高,笔者没有试过)

这个涉及到C语言编码,使用JNI调用Python C API来执行Python代码。通过C去调用python,再在Java中调用native方法去执行,需要将C语言编写的代码编译成动态链接库,并在Java代码中加载它。【过程较复杂,这里不做过多描述】

GPT示例:

  • 编写一个函数来执行Python代码
#include <Python.h>

jint JNICALL Java_PythonCaller_callPythonCode(JNIEnv *env, jobject obj) {
    PyObject *pModule = NULL, *pFunc = NULL, *pResult = NULL;
    jint result = 0;

    // 初始化Python解释器
    Py_Initialize();

    // 导入Python模块
    pModule = PyImport_ImportModule("test");
    if (pModule == NULL) {
        PyErr_Print();
        goto CLEANUP;
    }

    // 获取Python函数对象
    pFunc = PyObject_GetAttrString(pModule, "get_number");
    if (pFunc == NULL || !PyCallable_Check(pFunc)) {
        PyErr_Print();
        goto CLEANUP;
    }

    // 调用Python函数并获取结果
    pResult = PyObject_CallObject(pFunc, NULL);
    if (pResult == NULL) {
        PyErr_Print();
        goto CLEANUP;
    }

    // 将Python结果转换为Java整数类型
    result = (jint) PyLong_AsLong(pResult);

CLEANUP:
    // 释放Python对象和解释器资源
    Py_XDECREF(pResult);
    Py_XDECREF(pFunc);
    Py_XDECREF(pModule);
    Py_Finalize();

    return result;
}

  • 在Java代码中调用该函数
public class PythonCaller {
    static {
        System.loadLibrary("callpython");
    }

    public native int callPythonCode();

    public static void main(String[] args) {
        PythonCaller caller = new PythonCaller();
        int result = caller.callPythonCode();
        System.out.println("Result: " + result);
    }
}

  • 将C语言编写的代码编译成动态链接库
gcc -shared -fpic -I /usr/include/python3.6m -o libcallpython.so callpython.c

参考博客

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值