跳了N个坑又爬出来的Python调用JAVA传参收参(多图详细指导!)

本文详细介绍了Python如何通过os.popen调用Java程序并传递参数,解决跨语言数据交互难题,特别适合初学者及需要简单参数传递的场景。
Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

做为一个几乎没用过java的深度学习相关人员,在进行Python调用Java时,进入了n个深坑。在过去的1周里,头发少了很多。(在打这句话的时候,又发现桌子上的一根头发。。。)
把我能想到的方法发出来,给大家些启发,如果有更方便稳定的方法请一定告诉我。谢谢


话不多说

首先说一个前提,如果只是想向一个java程序传递若干个参数,然后收到java运算后的结果,那么本文的方法会非常简单实用(因为复杂的方法的坑我已经跳过了)。如果是比较复杂的情况,请安装jpype,安装方法可以看我的另外一篇博客。

进入正题

首先,请确定你的java JDK的版本,如果要在服务器上做工程,也请确定服务器上JKD的版本。在ide中编译的环境要于最终java运行的环境的jdk一致,否则会出现这种问题:

Exception in thread “main” java.lang.UnsupportedClassVersionError: Unsupported major.minor version 52.0

在这里插入图片描述

这个百度下就知道是版本不一致的问题,mac用户这个时候就百度下安装一个合适版本的jdk,win用户就比较简单了。
版本在cmd/terminal

java -version

就行了,看一下你的目标版本

先说下原理思路

思路就是python运行一个脚本,在shell里调用java程序,并且传递参数,然后读取java运行后的结果

JAVA部分

首先我们要在main函数里,设定外部传入的数据,可以在main中添加:


    public static void main(String[] args) {
        String data0= args[0];
        String data1 = args[1];
        xxxxxxx(data0,data1);
    }

data0和data1就是我们要传入的数据,xxxx就是需要这2个参数的 函数,看着改吧。

改好.java文件以后,我们就进行打包打成jar包的环节
很简单,大家不要出错,出错会很麻烦

1

在这里插入图片描述
File

2

在这里插入图片描述

project structure

3

在这里插入图片描述
artifact 加号
在这里插入图片描述
不要选empty选下面那个~~~·
在这里插入图片描述

选择你的主类,一定要选哦~

最后别忘了把你的lib都include进去,就是吧include in project build勾选上

okJAVA部分要结束了

build一下,在Artfact那个界面里,把地址记录一下
在这里插入图片描述
就是那个output地址,去那里把我们打好的jar包拿到吧~哈哈哈,结束一大半了~

Python部分

Python部分的核心在于os.popen这个指令
原理就是用python在cmd里运行

java -jar jar.jar

这个指令

然后加上你要传递的参数

java -jar jar.jar arg0 arg1

注意这个部分arg0和arg1中间要有个空格,然后从cmd里拿出运行的结果

相信看这个文章的主要是python用的多的人,我就简短点。
大家可以选择自己的方法,大家自由发挥。
因为我这个方法的缺点就是popen这个函数是buff上线的,我测试传递一个base64的东东的时候,就无法传递。。。。

command = "java -jar test.jar"
arg0 = "/Users/documents/lilili.jpg"
arg1 = "/Users/documents/lalala.jpg"
cmd = [command,arg0,arg1]
new_cmd = " ".join(cmd)
f = os.popen(new_cmd)
d = f.read()
print(d)
print(type(d))
f.close()

最后JAVA的输出就会保存在这个d里~
记得要import os哦~
在这里插入图片描述

ok

差不多就是这样了~
要是有小伙伴知道如果能够简单的传递base64这种比较长的参数的方法,请一定要告诉我哦~

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>我们考了用户提供的三个引用,来详细解释函数传参的方式。根据引用[1]和引用[2],函数传参主要有三种方式:值传递、地址传递(指针传递)和引用传递。同时,引用[3]展示了Python传参方式,包括位置数、默认数、可变数等。下面我们将结合这些内容,详细说明函数传参的方式。 ### 1. **值传递(Pass by Value)** - **定义**:将实的值复制一份传递给形,函数内部对形的修改不会影响实。 - **特点**: - 形和实占用不同的内存空间。 - 函数内修改形的值,不会改变实的值。 - **适用场景**:基本数据类型(如整数、浮点数、字符等)的传递。 - **示例(C++)**: ```cpp void swap(int a, int b) { int temp = a; a = b; b = temp; // 只交换了形的值,实不受影响 } int main() { int x = 1, y = 2; swap(x, y); // 调用后,x仍为1,y仍为2 return 0; } ``` - **引用说明**:引用[1]指出:“(1)形和实各占一个独立的存储空间。(2)形的存储空间是函数被调用时才分配的...然后将各实传递给形,这是形就得到了实的值。”[^1] ### 2. **地址传递(指针传递,Pass by Pointer/Address)** - **定义**:将实的地址传递给形(形为指针类型),函数内部通过指针间接访问实,从而修改实的值。 - **特点**: - 形和实共享同一块内存地址。 - 函数内通过指针修改数据,会直接影响实。 - **适用场景**:需要修改实或传递大型数据结构(避免复制开销)时。 - **示例(C++)**: ```cpp void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; // 通过指针交换实的值 } int main() { int x = 1, y = 2; swap(&x, &y); // 调用后,x变为2,y变为1 return 0; } ``` - **引用说明**:引用[1]强调:“地址传递与值传递的不同在于,它把实的存储地址传送给形,使得形指针和实指针指向同一块地址。因此,被调用函数中对形指针所指向的地址中内容的任何改变都会影响到实。”[^1] ### 3. **引用传递(Pass by Reference)** - **定义**:将实的别名(引用)传递给形,形和实是同一个变量。 - **特点**: - 形和实是同一个变量,占用相同的内存空间(地址相同)。 - 对形的修改直接作用于实。 - 避免了复制开销,尤其适合传递大型对象。 - **适用场景**:需要修改实或传递大型对象(如类实例)。 - **示例(C++)**: ```cpp void swap(int &a, int &b) { int temp = a; a = b; b = temp; // 直接交换实的值 } int main() { int x = 1, y = 2; swap(x, y); // 调用后,x变为2,y变为1 return 0; } ``` - **引用说明**:引用[2]指出:“传引用时,形和实是同一个变量,即使用相同的内存空间,二者有相同的地址...对引用数值的修改,会在退出函数后体现在主调函数中”[^2]。 ### 4. **其他传参方式(以Python为例)** Python中的数传递本质上是“对象引用传递”,但根据使用方式可分为种形式: - **位置数(Positional Arguments)**:按数位置顺序传递。 ```python def demo(name, age): print(f"Name: {name}, Age: {age}") demo("Alice", 25) # 位置传参 ``` - **关键字数(Keyword Arguments)**:按数名指定传递。 ```python demo(age=30, name="Bob") # 关键字传参 ``` - **默认数(Default Arguments)**:为数提供默认值,调用时可省略。 ```python def demo(name, age, sex='男'): # 默认数 print(f"Name: {name}, Age: {age}, Sex: {sex}") demo("张三", 19) # 使用默认性别'男' ``` - **可变数(Variable-Length Arguments)**: - `*args`:接任意数量的位置数,存储为元组。 ```python def fun(*args): print(f"早饭吃的是: {args}") fun("豆浆", "面包", "烤串") # 输出: 早饭吃的是: ('豆浆', '面包', '烤串') ``` - `**kwargs`:接任意数量的关键字数,存储为字典。 ```python def ffu(**kwargs): print(f"学生列表为: {kwargs}") ffu(name='张三', age=18, id='1001') # 输出: 学生列表为: {'name': '张三', 'age': 18, 'id': '1001'} ``` - **混合使用**:可组合数类型(顺序:位置数、默认数、`*args`、`**kwargs`)。 ```python def kfc(*args, **kwargs): print(f"早饭有{args},价格为:{kwargs}") kfc('豆浆', '三明治', '鸡蛋', 豆浆='10¥', 三明治='20¥', 鸡蛋='5¥') ``` - **引用说明**:引用[3]展示了Python中位置传参、默认数、可变数的使用示例[^3]。 ### 总结 | 传参方式 | 特点 | 语言示例 | |--------------|----------------------------------------------------------------------|-------------------| | **值传递** | 复制实值,形修改不影响实 | C++基本类型 | | **地址传递** | 传递实地址,通过指针修改实 | C/C++指针 | | **引用传递** | 形是实的别名,直接修改实 | C++引用 | | **位置数** | 按数位置顺序传递 | Python, Java等 | | **关键字数**| 按数名指定传递 | Python, Kotlin等 | | **默认数** | 数有默认值,调用时可省略 | 语言支持 | | **可变数** | 接任意数量的位置数(`*args`)或关键字数(`**kwargs`) | Python | > **注意**:不同语言对传参方式的实现有差异: > - C/C++:明确支持值传递、地址传递、引用传递。 > - Java:严格按值传递(对象传递的是引用的副本)。 > - Python数传递均为对象引用(可变对象可被函数修改,不可变对象则不能)。 如果您有特定语言的传参问题,可进一步提问! §§相关问题§§ 1. 值传递和引用传递在内存管理上有何差异? 2. Python中如何正确使用可变对象(如列表)作为函数数? 3. 在C++中,何时应该使用指针传递而非引用传递? 4. 如何避免因传参方式选择不当导致的程序错误? 5. 函数式编程语言(如Haskell)中的传参方式有何特点? [^1]: 函数传参的三种方式(详细)。 [^2]: 函数传参的三种方式。 [^3]: 函数的传参方式。</think>### 函数传参方式详解 函数传参是编程中的核心概念,决定了数据如何从调用者传递给函数。根据引用内容,传参方式主要分为三类,每种方式在内存管理、数据修改和语法实现上都有显著差异: #### 1. **值传递 (Pass by Value)** - **核心机制**: 将实的**值复制**一份传递给形,形与实占用完全独立的存储空间。 - **特点**: - ✅ 函数内修改形**不会影响**原始实 - ✅ 适合传递基本数据类型(整数、浮点数等) - ⚠️ 大对象复制可能产生性能开销 - **内存示意**: ``` 调用前: [实] = 0x1000 (值: 10) 调用时: [形] = 0x2000 (值: 10) // 完全独立的新内存 ``` - **示例(C++)**: ```cpp void modify(int val) { val = 20; // 只修改副本 } int main() { int a = 10; modify(a); // a 仍为 10 } ``` - **引用支持**: "形和实各占一个独立的存储空间" [^1] #### 2. **地址传递 / 指针传递 (Pass by Pointer/Address)** - **核心机制**: 传递实的**内存地址**,形指向实内存的指针。 - **特点**: - ✅ 函数内通过指针修改数据会**直接影响实** - ✅ 避免大数据复制开销 - ⚠️ 需显式使用指针操作符(`*`, `->`) - **内存示意**: ``` 调用前: [实] = 0x1000 (值: 10) 调用时: [形] = 0x3000 (值: 0x1000) // 存储实地址 ``` - **示例(C++)**: ```cpp void modify(int* ptr) { *ptr = 20; // 通过指针修改原始数据 } int main() { int a = 10; modify(&a); // a 变为 20 } ``` - **引用支持**: "形指针和实指针指向同一块地址,对地址内容的改变会影响实" [^1] #### 3. **引用传递 (Pass by Reference)** - **核心机制**: 形成为实的**别名**,两者共享同一内存空间。 - **特点**: - ✅ 函数内修改形**直接影响实** - ✅ 语法简洁(无需指针操作符) - ✅ 避免复制开销 - ⚠️ 部分语言专属(如 C++) - **内存示意**: ``` 调用前: [实] = 0x1000 (值: 10) 调用时: [形] = 0x1000 // 与实相同地址 ``` - **示例(C++)**: ```cpp void modify(int &ref) { ref = 20; // 直接修改原始数据 } int main() { int a = 10; modify(a); // a 变为 20 } ``` - **引用支持**: "形和实是同一个变量,使用相同内存空间" [^2] --- ### 高级传参方式(Python 示例) Python 在基础传参(对象引用传递)上扩展了种实用方式: #### 1. **默认数** ```python def register(name, age, country="China"): # country 有默认值 print(f"{name}, {age}岁, 国籍: {country}") register("张三", 25) # 输出: 张三, 25岁, 国籍: China ``` #### 2. **可变位置(`*args`)** ```python def sum_values(*args): # 接任意数量位置数 return sum(args) print(sum_values(1, 2, 3)) # 输出: 6 ``` #### 3. **可变关键字(`**kwargs`)** ```python def print_profile(**kwargs): # 接任意数量关键字数 for key, value in kwargs.items(): print(f"{key}: {value}") print_profile(name="李四", age=30, occupation="工程师") ``` #### 4. **混合使用** ```python def complex_example(a, b=10, *args, **kwargs): print(f"a={a}, b={b}, args={args}, kwargs={kwargs}") complex_example(1, 2, 3, 4, name="王五", id=1001) # 输出: a=1, b=2, args=(3,4), kwargs={'name':'王五','id':1001} ``` --- ### 关键差异总结 | 特性 | 值传递 | 地址传递 | 引用传递 | |---------------------|---------------|---------------|---------------| | **内存空间** | 独立副本 | 共享原始地址 | 共享原始空间 | | **修改影响实** | ❌ 不影响 | ✅ 影响 | ✅ 影响 | | **大对象性能** | 差(需复制) | 优 | 优 | | **典型语言** | C 基本类型 | C/C++ | C++/Rust | | **语法复杂度** | 简单 | 中等(需指针)| 简单 | > **Python/Java 特别说明**: > 这类语言采用 **对象引用传递**,对不可变对象(如数字、字符串)表现为值传递效果,对可变对象(如列表、字典)则表现为引用传递效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值