本章概述
python调用java,关键的一点是python 类型和 Java 类型之间的转换。这个功能借助JPype完成,Jpype提供了一系列API,帮助使用者完成python参数到java参数的转换。 本章的目的是尽可能覆盖java参数类型,通过示例演示如何将python数据类型转换为指定的java数据类型。
参数类型转换参考表
这部分原文链接如下: http://jpype.sourceforge.net/doc/user-guide/userguide.html#conversion
下图横坐标代表java类型,竖坐标代表python类型,其中以“J”开头的,是JPype封装的类型,由于JPype是python的一个模块,所以Jpype封装的类型在这里也认为是python类型。
JPype 定义了 Python 对象和 Java 类型之间“匹配”的不同层次。这些级别是:
- 下图空白单元格:代表对应的两个类型没有办法转换。
- 单元格为“I”的:JPype 将根据需要进行转换,即隐式转换。
- 单元格为“X”的:与“I”对应,是显示转换,但优先级高于隐式转换。比如有的类型同时支持隐式转换和显示转换,如果明确指定显示转换,则转换过程就是显示转换。举个例子,java的byte类型,对应到python中int、long、JByte类型都可以转换为byte类型。如果一个java函数的参数是byte类型,那么在python中调用这个java函数时,参数值可以直接填写python中的数字(python2才区分Long类型, python3统一划分为数字类型),这时是把参数自动隐式转换java的byte类型。参数值也可以填JByte(2)这样的显示转换,这时是把参数值显示转换给java中的byte类型,此时隐式转换是不生效的。
 对于上图单元格中的数字,是对该单元格所对应的转换关系的补充说明: (1) 如果 Python 值适合 java 本机类型,则会发生转换。
(2) 如果python字符串或unicode长度为1,则发生转换
(3) 所需对象的类型必须与java.lang.String ( java.lang.Object , java.util.Comparable )兼容
(4) 维数必须匹配,类型必须兼容
(5) 仅当需要的类型为java.lang.Object 时
(6) 仅当 JObject 包装器的指定类型是兼容的数组类时。
(7) 仅当所需的类型与包装器的指定类型兼容时。不考虑 java 对象的实际类型。
(8) 仅当requireds 类型与Java Object 实际类型兼容时。
(9) 仅当所需类型为java.lang.Object或java.lang.Class 时
(10) 只有 True 和 False 值被隐式转换为布尔值。
示例
下面通过示例演示python类型与java类型的转换,笔者为了使转换过程看起来更规范,都是使用显示转换。这样所有的转换统一依赖Jpype提供的API来完成。
byte
java :
package com.linchao;
public class myJpypeTest {
public int test_byte(byte param){
int res = param + 1;
return res;
}
public static void main(String[] args){
System.out.println("Jpype Test...");
}
}
python:
from jpype import JByte
def to_byte(param):
return JByte(param)
from jpype import JClass
import jpype
from TransferParam import to_byte
if __name__ == "__main__":
jpype.startJVM(classpath=r"D:\myProjects\java\JpypeTest\out\artifacts\JpypeTest_v0_1\JpypeTest_v0.1.jar")
myJpypeTest = JClass("com.linchao.myJpypeTest")()
res = myJpypeTest.test_byte(to_byte(100))
print(res)
输出结果
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
101
Process finished with exit code 0
第一个示例,显示了java和python的全部代码。 后面的示例,为了更清晰的排版和显示主要内容,只贴关键代码。不过完整的代码可以到指定链接获取。
short
java:
public String test_short(short param){
int res = param + 1;
return param + "+" + "1" + "=" + res;
}
python:
def to_short(param):
return JShort(param)
res = myJpypeTest.test_short(to_short(100))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
100+1=101
Process finished with exit code 0
int
java:
public String test_int(int param){
int res = param + 1;
return param + "+" + "1" + "=" + res;
}
python:
def to_int(param):
return JInt(param)
res = myJpypeTest.test_int(to_int(200))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
200+1=201
Process finished with exit code 0
long
java:
public String test_long(long param){
long res = param + 1;
return param + "+" + "1" + "=" + res;
}
python:
def to_long(param):
return JLong(param)
res = myJpypeTest.test_long(to_long(300))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
300+1=301
Process finished with exit code 0
float
java:
public String test_float(float param){
float res = param + 1;
return param + "+" + "1" + "=" + res;
}
python:
def to_float(param):
return JFloat(param)
res = myJpypeTest.test_float(to_float(400.54))
print(res)
"D:\Program Files\Python39\python.exe" "D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
400.54+1=401.54
Process finished with exit code 0
double
java:
public String test_double(double param){
double res = param + 1;
return param + "+" + "1" + "=" + res;
}
python:
def to_double(param):
return JDouble(param)
res = myJpypeTest.test_double(to_double(520.54))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
520.54+1=521.54
Process finished with exit code 0
boolean
java:
public String test_boolean(boolean param){
if(param == true){
return "param is true";
}
else {
return "param is false";
}
}
python:
def to_boolean(param):
return JBoolean(param)
res = myJpypeTest.test_boolean(to_boolean(False))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
param is false
Process finished with exit code 0
res = myJpypeTest.test_boolean(to_boolean(True))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
param is true
Process finished with exit code 0
char
java:
public String test_char(char param){
int a = param;
return "ascii: " + param + "->" + a;
}
python:
def to_char(param):
return JChar(param)
res = myJpypeTest.test_char(to_char("a"))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
ascii: a->97
Process finished with exit code 0
String
java:
public String test_String(String param){
return "Hello! " + param ;
}
python:
def to_String(param):
return JString(param)
res = myJpypeTest.test_String(to_String("Devin"))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
Hello! Devin
Process finished with exit code 0
Array
在java中,数组类型根据数组元素,可以是整形数组、字符串数组、某种对象的数组等等。但无论是什么类型的数组,在jpype中,都是通过JArray这个API来实现。 示例
int[]: JArray(JInt)
float[]: JArray(JFloat)
String[]: JArray(JString)
JArray API返回一个JClass对象,通过传入参数调用这个对象即可以得到一个数组对象。调用这个对象有两种传参方式,第一种是传入一个整数,会得到一个长度为整数的数组,数组中的元素值默认初始化值(int是0,String是None),第二种方式是传入序列,得到一个长度为序列长度,元素值为序列值的数组。 看代码演示: 先演示int[], java:
public int test_Array(int[] param){
int sum = 0;
for(int i : param){
sum = sum + i;
}
return sum;
}
python:
def to_int_array(param):
return JArray(JInt)(param)
res = myJpypeTest.test_Array(to_int_array(5))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
0
Process finished with exit code 0
res = myJpypeTest.test_Array(to_int_array([1,2,3,4,5]))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
15
Process finished with exit code 0
再演示String[] Java:
public String test_Array(String[] param){
String sum = "";
for(String i : param){
sum = sum + i;
}
return sum;
}
python:
def to_String_array(param):
return JArray(JString)(param)
res = myJpypeTest.test_Array(to_String_array(["我", "爱", "中", "国"]))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
我爱中国
Process finished with exit code 0
最后,演示一个自定义对象数组。 这个例子是在java中自定义对象,然后定义一个函数,其输入参数是自定义对象。最后在python中调用这个函数。 首先,看看在java中自定义的对象,这是一个描述动物的对象,有名字、年龄、别名三个私有属性,对外提供了一个接口返回一段自我介绍。
package params;
public class Animals {
private String name="";
private int age=0;
private String alias="";
public Animals(String name, int age, String alias) {
this.name = name;
this.age = age;
this.alias = alias;
}
public String sayHello(){
return "你好!我是" + this.name + ",今年" + this.age + "岁, 人们通常叫我"+ this.alias;
}
}
java中待调用的目标函数:
public List<String> test_Array(Animals[] params){
List<String> res = new ArrayList();
for(Animals animal: params){
res.add(animal.sayHello());
}
return res;
}
接下来是python中,自定义对象数组的转换:
def to_Animal_array(param, Animal):
return JArray(Animal)(param)
names = ["假老练", "风车车", "莽哥"]
ages = [3,2,4]
alias = ["猫儿", "耗子", "狗儿"]
Animal = JClass("params.Animals")
animals = []
for i in range(3):
animals.append(Animal(to_String(names[i]), to_int(ages[i]), to_String(alias[i])))
res = myJpypeTest.test_Array(to_Animal_array(animals, Animal))
for i in res:
print(i)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
你好!我是假老练,今年3岁, 人们通常叫我猫儿
你好!我是风车车,今年2岁, 人们通常叫我耗子
你好!我是莽哥,今年4岁, 人们通常叫我狗儿
Process finished with exit code 0
这是一个较为综合性的示例,还涉及到了下面才要描述的自定义对象类型转换。如果这里暂时没看懂,没关系,先看下面,然后再回过头来看这个示例。
自定义Class对象
依然使用Animals对象:
package params;
public class Animals {
private String name="";
private int age=0;
private String alias="";
public Animals(String name, int age, String alias) {
this.name = name;
this.age = age;
this.alias = alias;
}
public String sayHello(){
return "你好!我是" + this.name + ",今年" + this.age + "岁, 人们通常叫我"+ this.alias;
}
}
public String test_class(Animals animals){
return animals.sayHello();
}
在python中调用这个函数:
# Animal类构造函数接受三个参数,但param是个序列,所以用了*
def to_java_class(cls, param):
# 获得java class
java_class = JClass(cls)
# 调用java class的构造函数示例化对象
return java_class(*param)
res = myJpypeTest.test_class(to_java_class("params.Animals", [to_String("假老练"), to_int(3), to_String("猫儿")]))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
你好!我是假老练,今年3岁, 人们通常叫我猫儿
Process finished with exit code 0
Tips:
python中的 JClass("params.Animals")
类似java中的 import params.Animals;
List
对于java中List类型对象,jpype使用java.util.ArrayList 这个api来转换。 以List<String> 为例: Java:
public String test_List(List<String> params){
String res = "";
for(String param : params){
res = res + param;
}
return res;
}
python:
def to_list(param):
return java.util.ArrayList(param)
res = myJpypeTest.test_List(to_list(["新","年","快","乐"]))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
新年快乐
Process finished with exit code 0
Map
java中的Map下常见的是HashMap和LinkedHashMap。 分别对应jpype的java.util.HashMap、java.util.LinkedHashMap 两个API。使用方法是相似的。 以HashMap为例子。 java:
public String test_Map(HashMap<String, Integer> params){
int age = params.get("age");
int rmb = params.get("RMB");
return "age:"+age+" rmb:"+rmb;
}
python:
def to_HashMap(param):
return java.util.HashMap(param)
res = myJpypeTest.test_Map(to_HashMap({to_String("age"):to_int(18), to_String("RMB"):to_int(999999)}))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
age:18 rmb:999999
Process finished with exit code 0
Enum
java:
package params;
public enum testEnum {
RED("红色"), GREEN("绿色"), BLANK("白色"), YELLO("黄色");
private String color;
testEnum(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
public String test_Enum(testEnum testenum){
return testenum.getColor();
}
python:
def to_Enum(cls, param):
# 获得枚举类
java_class = JClass(cls)
# 获取枚举对象中的成员
return getattr(java_class, param)
# 测试自Enum类型转换
res = myJpypeTest.test_Enum(to_Enum("params.testEnum", "RED"))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
红色
Process finished with exit code 0
总结
本文描述如何通过jpype完成python类型到java类型的转换。 包含了java原生类型,以及自定义对象类型、数组类型、枚举类型、List类型、Map类型。
示例源码:
https://github.com/linchao001/testJpype
|