下面我将详细介绍几种主流的实现方式,从最简单、最通用的到性能最高的,并附上完整的代码示例和优缺点分析。

核心思路
无论采用哪种技术,其核心思想都是相似的:
- Java 进程:你的 Java 应用程序作为主进程。
- 通信桥梁:通过某种机制(如标准输入/输出、Socket、共享内存等)让 Java 进程能够与 Python 解释器进行通信。
- Python 子进程:Java 启动一个 Python 解释器作为子进程,并让它执行指定的 Python 脚本。
- 数据交换:Java 将参数传递给 Python,Python 执行完毕后将结果(如字符串、数字、JSON)返回给 Java。
使用 Runtime.exec() 或 ProcessBuilder (原生 Java)
这是最基础、最直接的方法,不依赖任何第三方库,Java 通过执行操作系统的命令来启动 Python 解释器。
工作原理
Java 使用 Runtime.getRuntime().exec() 或 ProcessBuilder 类来执行一个命令行指令,python your_script.py arg1 arg2,Java 和 Python 子进程通过标准输入流和标准输出流进行通信。
代码示例
Python 脚本 (my_script.py)

这个脚本会从命令行参数中读取一个名字,计算一个斐波那契数,然后将结果以 JSON 格式输出到标准输出。
# my_script.py
import sys
import json
import time
# 从命令行参数获取输入
# sys.argv[0] 是脚本名,所以从 1 开始
if len(sys.argv) > 1:
name = sys.argv[1]
try:
n = int(sys.argv[2])
except (IndexError, ValueError):
n = 10 # 默认值
else:
name = "World"
n = 10
# 模拟一个耗时操作
print(f"Python: Hello, {name}! Calculating Fibonacci for {n}...", file=sys.stderr)
time.sleep(2) # 模拟计算耗时
def fibonacci(num):
a, b = 0, 1
for _ in range(num):
a, b = b, a + b
return a
result = fibonacci(n)
# 将结果以 JSON 格式输出到标准输出,方便 Java 解析
output_data = {
"greeting": f"Hello {name} from Python!",
"fibonacci_result": result,
"status": "success"
}
print(json.dumps(output_data))
Java 代码 (JavaPythonCaller.java)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class JavaPythonCaller {
public static void main(String[] args) {
// Python 脚本的路径和参数
String scriptPath = "path/to/your/my_script.py";
String name = "Java User";
int number = 15;
// 构建命令
// 注意:Windows 下 python 可能是 "python.exe",Linux/macOS 下是 "python3" 或 "python"
String[] command = {
"python",
scriptPath,
name,
String.valueOf(number)
};
try {
// 使用 ProcessBuilder 启动进程,它比 Runtime.exec() 更灵活
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true); // 将错误流合并到输出流,方便处理
Process process = pb.start();
// 读取 Python 脚本的输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line);
}
// 等待 Python 进程执行完毕
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("Java: Python script executed successfully.");
System.out.println("Java: Received output from Python:");
System.out.println(output.toString());
} else {
System.err.println("Java: Python script failed with exit code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
优点
- 无依赖:不需要任何额外的 Java 库,是 Java 的标准功能。
- 简单直接:概念简单,易于理解和实现。
缺点
- 性能开销大:每次调用都需要创建一个新的 Python 进程,启动和销毁进程的开销很大。
- 通信复杂:数据交换依赖于字符串(通过标准输入/输出),处理复杂数据结构(如列表、字典)非常麻烦,容易出错。
- 错误处理困难:难以捕获 Python 脚本内部的详细错误信息。
- 平台相关:Python 解释器的路径(
pythonvspython3vspython.exe)在不同操作系统上可能不同。
使用第三方库 (推荐)
为了解决原生方法的痛点,社区涌现出许多优秀的第三方库,它们封装了进程间的通信,提供了更高效、更便捷的 API。
Junrar
这是一个专门用于在 Java 中调用 Python 的库,它通过标准输入/输出与 Python 交互,但提供了非常友好的 API。
Maven 依赖:
<dependency>
<groupId>org.junrar</groupId>
<artifactId>junrar</artifactId>
<version>7.5.3</version> <!-- 请使用最新版本 -->
</dependency>
注意:
junrar这个名字可能引起误解,它最初是用于解压 RAR 文件的,但其作者后来扩展了功能来支持 Python 调用,请确保你添加的是正确的库。
代码示例:
import org.junrar.Python;
import org.junrar.PythonExecutionException;
import org.json.JSONObject;
public class JunrarExample {
public static void main(String[] args) {
try {
// 创建 Python 执行器
Python python = new Python();
// 执行 Python 代码片段
String pythonCode = "import json\n" +
"name = 'Junrar User'\n" +
"result = {'message': 'Hello from Junrar!', 'value': 42}\n" +
"print(json.dumps(result))";
// 执行代码并获取输出
String output = python.execute(pythonCode);
// 解析 JSON 输出
JSONObject resultJson = new JSONObject(output);
System.out.println("Java: Received from Python: " + resultJson.getString("message"));
System.out.println("Java: Value: " + resultJson.getInt("value"));
} catch (PythonExecutionException e) {
System.err.println("Python execution failed: " + e.getMessage());
e.printStackTrace();
}
}
}
优点
- API 友好:比手动管理
Process简单得多。 - 易于使用:可以直接执行字符串形式的 Python 代码,也可以执行脚本文件。
缺点
- 仍有进程开销:本质上还是在创建新的 Python 进程,性能瓶颈依然存在。
- 依赖库:需要引入第三方库。
Pyrolite
这是一个更高级的库,它使用 Pyro (Python Remote Objects) 协议,它不通过标准输入/输出,而是通过 Socket 进行通信,性能远高于基于标准流的方法。
工作原理:
- 一个 Python 脚本作为 Pyro 服务器启动,并暴露一些可调用的函数或对象。
- Java 客户端连接到这个 Pyro 服务器。
- Java 像调用本地方法一样直接调用 Python 端暴露的函数。
- 数据序列化是通过
pickle(Python)和Pyrolite(Java)完成的,支持复杂对象。
Maven 依赖:
<dependency>
<groupId>net.razorvine</groupId>
<artifactId>pyrolite</artifactId>
<version>5.13</version> <!-- 请使用最新版本 -->
</dependency>
Python 服务器端 (pyro_server.py)
import Pyro4
import time
# Pyro4 配置,使用更可靠的线程池
Pyro4.config.SERVERTYPE = "thread"
@Pyro4.expose
class PyroService(object):
def hello(self, name):
print(f"Python (Pyro): Received request from {name}")
time.sleep(1) # 模拟耗时操作
return f"Hello, {name}! This is a Pyro response."
# 启动一个名字服务器,让客户端可以找到我们的服务
daemon = Pyro4.Daemon()
ns = Pyro4.locateNS()
uri = daemon.register(PyroService)
ns.register("example.pyro_service", 