python调用java之Jpype实现java接口
python调用java之Jpype实现java接口
python实现java接口
概述
本文介绍在python中实现java接口。
JPype 可以通过使用装饰器或手动创建 JProxy 来实现 Java 接口。Java 只支持代理接口,因此我们不能扩展现有的 Java 类。
笔者在测试领域,通常使用python调用java程序,达到在通过python测试java程序的目的。因此不能很理解在python中实现java接口的意义。如果有人知道,请留言告知。
了解的一个意义是:在python中实现java接口,然后作为回调函数传递给java api。
下面介绍下在java中,一个函数的参数是一个回调函数的例子。
java程序
java接口
package params;
public interface testInterface {
int testMethod();
}
java测试函数
该函数的第二个参数是一个实现了testInterface接口的对象,但这个接口java提供方没有实现,而是留给调用方实现。
public int test_recall(int a, testInterface a_interface_obj){
int b = a_interface_obj.testMethod();
return a+b;
}
如果使用python调用test_recall函数,那么就需要在python中实现testInterface接口。
在python中实现java接口的两种方式
第一种:JImplements
JImplements是Jpype提供的一个装饰器对象,通过使用它来实现java接口的实现。但这个方法有个不友好的地方,下面遇到会介绍。
JImplements的使用示例
通过JImplements实现上文中的testInterface接口
# coding: utf-8
from jpype import JImplements, JOverride
@JImplements("params.testInterface")
class java_interface:
@JOverride
def testMethod(self):
return 99
调用java程序中的test_recall函数
res = myJpypeTest.test_recall(to_int(1), java_interface())
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
100
Process finished with exit code 0
我们通过使用JImplements装饰器在python中实现了testInterface接口,然后把其作为回调函数传给test_recall,完成test_recall调用。
JImplements不友好的地方
这个不友好的地方来源与python的一个知识点:
- python在导入模块时就会执行装饰器
按照笔者的编程风格,实现java接口,作为独立功能是单独放在一个python模块文件中,而调用java程序的代码放在另一个模块中。
其中java_interface.py是实现java接口的模块。
main.py是实现调用java程序的模块。
在main.py的顶部,会有
from java_interface import java_interface
来导入实现java接口的类。
因为JImplements是一个装饰器,所以在加载java_interface模块时就会执行,此时业务代码没有执行,jar包没有加载,jvm没有启动,所以JImplements执行会报JVM没有启动的错误。
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
Traceback (most recent call last):
File "D:\myProjects\python\test_JPype\main.py", line 5, in <module>
from java_interface import java_interface
File "D:\myProjects\python\test_JPype\java_interface.py", line 6, in <module>
class java_interface:
File "D:\Program Files\Python39\lib\site-packages\jpype_jproxy.py", line 136, in JProxyCreator
return _createJProxy(cls, *interfaces, **kwargs)
File "D:\Program Files\Python39\lib\site-packages\jpype_jproxy.py", line 80, in _createJProxy
actualIntf = _prepareInterfaces(cls, intf)
File "D:\Program Files\Python39\lib\site-packages\jpype_jproxy.py", line 51, in _prepareInterfaces
actualIntf = _convertInterfaces(intf)
File "D:\Program Files\Python39\lib\site-packages\jpype_jproxy.py", line 156, in _convertInterfaces
actualIntf.add(_jpype.JClass(item))
File "D:\Program Files\Python39\lib\site-packages\jpype_jclass.py", line 99, in __new__
return _jpype._getClass(jc)
jpype._core.JVMNotRunning: Java Virtual Machine is not running
从异常Traceback中可以看到,在
from java_interface import java_interface
这一步就报错了。
如果想顺利运行,除非在
from java_interface import java_interface
之前,就加载jar包启动jvm,但这对于代码风格来说不友好。
第二种:JProxy
首先编写一个python类,这个类包含了testInterface接口声明的方法。
class java_interface_1:
def testMethod(self):
return 99
然后,调用java程序,通过JProxy实现接口对象的实现。
# 测试python实现java接口作为回调函数
res = myJpypeTest.test_recall(to_int(1), JProxy("params.testInterface", inst=java_interface_1()))
print(res)
"D:\Program Files\Python39\python.exe" D:/myProjects/python/test_JPype/main.py
100
Process finished with exit code 0
遗憾的是,官方文档提到,JProxy是一个老式的API,新代码应该使用@JImplements注释,因为它将支持改进的类型安全和错误处理。
总结
本文介绍了两种方式,都可以在python中实现java接口。虽然两种方式都不完美,但满足实际需求是可以的。