python调用java之Jpype实现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接口。虽然两种方式都不完美,但满足实际需求是可以的。

示例源码

https://github.com/linchao001/testJpype

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 `jpype` 调用 Java 包需要先安装 `jpype` 库,可以使用 `pip` 命令进行安装: ``` pip install jpype1 ``` 然后,可以按照以下步骤使用 `jpype` 调用 Java 包并传参: 1. 首先,需要启动 JVM 进程,可以使用 `jpype.startJVM()` 函数来启动: ```python import jpype jpype.startJVM() ``` 2. 导入 Java 类: ```python java_class = jpype.JClass('com.example.MyClass') ``` 其中,`com.example.MyClass` 是要调用Java 类的全限定名。 3. 创建 Java 对象: ```python java_object = java_class() ``` 4. 调用 Java 方法: ```python result = java_object.myMethod('param1', 'param2') ``` 其中,`myMethod` 是要调用Java 方法名,`'param1'`、`'param2'` 是传递给 Java 方法的参数。 5. 关闭 JVM: ```python jpype.shutdownJVM() ``` 完整示例代码如下: ```python import jpype # 启动 JVM jpype.startJVM() # 导入 Javajava_class = jpype.JClass('com.example.MyClass') # 创建 Java 对象 java_object = java_class() # 调用 Java 方法 result = java_object.myMethod('param1', 'param2') # 关闭 JVM jpype.shutdownJVM() ``` 注意,如果 Java 类需要传递复杂类型的参数,需要先将 Python 对象转换为 Java 对象。可以使用 `jpype.java` 模块中的函数进行转换,例如: ```python import jpype # 启动 JVM jpype.startJVM() # 导入 Javajava_class = jpype.JClass('com.example.MyClass') # 创建 Java 对象 java_object = java_class() # 转换 Python 对象为 Java 对象 param1 = jpype.java.lang.String('hello') param2 = jpype.JArray(jpype.JInt)([1, 2, 3]) # 调用 Java 方法 result = java_object.myMethod(param1, param2) # 关闭 JVM jpype.shutdownJVM() ``` 在上面的示例中,`jpype.java.lang.String` 将 Python 字符串转换为 Java 字符串,`jpype.JArray` 将 Python 列表转换为 Java 数组。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值