一文速学-Python联通调用JAVA的桥梁PyJnius库详解

简介: 一文速学-Python联通调用JAVA的桥梁PyJnius库详解

前言


最近一直在研究HiveSQL的源码以及ANTLR包的源码,比较无奈的是工程上我还是偏向于使用Pycharm和python编程语言。其实编程语言选择都无所谓只是工具罢了,主要的是其中解析抽象树AST的思想以及方法。但是基础的语法方法需要掌握,比如Python调库以及引用,JAVA的import规则以及jar包的引用。要做成工程化的程序,程序员就必须有一定的工具使用能力,比如anaconda和IDEA的基础使用方法,做HiveSQL血缘分析的时候遇到了很多大坑以及众多BUG报错,对于自身代码能力和解决问题的能力也有一定的成长。好了废话不多说,就让我们来研究如何来使用该库实现相应功能吧。博主将长期维护自己博客的文章,如有披露错误或者不理解之处请尽情在评论区留下发言。希望能够帮助到需要掌握该库的各位。


一、PyJnius


PyJnius库正如文章标题,是一个用于访问Java类的Python库。PyJnius官网:Welcome to Pyjnius — Pyjnius 1.0a1 documentation


github:


GitHub - kivy/pyjnius: Access Java classes from Python


PyJnius库主要分为三个部分:


jnius

jnius_config

setup_sdist

现在的PyJnius库的版本为1.4.2。该库通过JVM虚拟机实现调用。


1.下载方式


方法一


直接通过在cmd命令提示符里面输入:


pip install pyjnius


但是这种方式很可能由于连接不稳定失败,建议换个源再下载:


pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pyjnius


conda的下载:


conda install -c conda-forge pyjnius


方法二


直接去Pypi上面下载whl文件也很快,毕竟现在连外网很不稳定,网速很慢。大家可以在本人资源列表上面下载whl匹配版本的文件:


pyjnius-1.4.2-cp37-cp37m-win32.whl-Python文档类资源-CSDN下载


下载whl文件之后进入cmd上面cd到当前下载的目录下面,pip该文件就好了。


2.相关依赖


由于是调用的JAVA的Class类那肯定需要的依赖比较多,需要安装cython这个库,如果大家有装acaconda的话去环境里面下载就好了,而pyjnius在anaconda里面是没有的,也不知道是不是我版本太低了没有找到。当然网络连接稳定的直接pip就好了,接连的话要在下载一个gcc编译器:


yum install gcc gcc-++
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple cython

当然自然需要JAVA环境了,需要大家自行下载JDK,我相信这个是个程序员应该都装过,那么JAVA_HOME应该都配置过了,但是这里需要再额外配置一下环境变量PATH,需要找到jvm.dll:


C:\Program Files\Java\jdk1.7.0_79\jre\bin\server


其中java的中的bin目录下server里面就有java的jvm.dll文件了。


二、使用测试


我们可以试试调用JAVA自身的一些类来使用,就类似于python自带的原始库。我建议是如果大家想要使用其他的jar包的话最好是使用pycharm来实现,Jupyter是我主要用的一个编译器但是使用jnius的话config设置路径的话会报错,如果使用pycharm就没有事。


from jnius import autoclass
Stack = autoclass('java.util.Stack')
stack = Stack()
stack.push('hello world')

fe800335d7fd4276852eef0678418550.png

如果返回类型不是Python类型,Pyjnius使用Java反射提供一个新的autoclass()。


1. System = autoclass('java.lang.System')
2. System


3db0d39dbca7495e955d4e2400835a95.png

System.out

83481d5d76e746609ee21699d01a1aed.png

递归反射可以提供一个Reflection返回的Java对象的适当对象。


三、Reflection类


用于反映Java类的基。其思想是对这个JavaClass进行子类化,添加一些JavaMethod、JavaStaticMethod,JavaField和JavaStaticField。


类似这种形式:

from jnius import JavaClass, MetaJavaClass
class Stack(JavaClass):
    __javaclass__ = 'java/util/Stack'
    __metaclass__ = MetaJavaClass

__metaclass__: 必须设置为MetaJavaClass,否则,声明的所有方法/字段将不会链接到JavaClass。

__javaclass__:表示Java类名,格式为“org/lang/class”(例如“Java/util/Stack”),而不是“org.lang.class”。

__javaconstructor__:如果未设置,假设默认构造函数不带参数。否则,它可以是构造函数的所有可能签名的列表。


例如,字符串java类的反射如下所示:

class String(JavaClass):
    __javaclass__ == 'java/lang/String'
    __metaclass__ = MetaJavaClass
    __javaconstructor__ == (
        '()V',
        '(Ljava/lang/String;)V',
        '([C)V',
        '([CII)V',
        # ...
    )

还有更多类就不一一详说了,核心类就这三个,更多的类都是基于此衍生出来的


四、Reflection函数


1.jnius.autoclass(name)


返回表示从name传递的类的JavaClass。名称必须采用a.b.c格式,而不是a/b/c格式。

from jnius import autoclassQ
autoclass('java.lang.System')

af20477c99344783852bec1070e146ee.png

当JAVA出现了Python的关键字时(例如from、class等)的成员。需要使用getattr()来访问该成员,然后才能调用它:

from jnius import autoclass
func_from = getattr(autoclass('some.java.Class'),'from')
func_from()

SomeClass还有一个特例。类文本,可以将其作为SomeClass的结果找到。getClass()或__javaclass__ python属性中。


Python中的Java类实现


从Python类创建Java类的基础。可以完全用Python实现java接口。

实际上,将创建一个Python类,它模仿声明的__javainterfaces__列表。当将这个类的实例提供给Java时,Java将只接受它并调用声明的接口方法。在幕后,我们正在捕获调用,并将其重定向到使用声明的Python方法。创建的类将充当Java接口的代理。

但是需要至少定义__javainterfaces__属性,并使用java_method()修饰符声明java方法。

from jnius import PythonJavaClass, java_method
class PythonListIterator(PythonJavaClass):
    __javainterfaces__ = ['java/util/ListIterator']
    def __init__(self, collection, index=0):
        super(TestImplemIterator, self).__init__()
        self.collection = collection
        self.index = index
    @java_method('()Z')
    def hasNext(self):
        return self.index < len(self.collection.data) - 1
    @java_method('()Ljava/lang/Object;')
    def next(self):
        obj = self.collection.data[self.index]
        self.index += 1
        return obj


__javainterfaces__:要代理的Java接口列表,格式为“org/lang/Class”(例如“Java/util/Iterator”),而不是“org.lang.Class”。

__javacontext__:指示要使用的类加载器,“系统”或“应用程序”。默认值为“系统”。


jnius.java_method


与PythonJavaClass一起使用的装饰函数。java_signature必须与接口的所需签名匹配。默认情况下,方法的名称将是Python方法的名称。如果多个签名具有相同的Java方法名,仍然可以强制执行。


class PythonListIterator(PythonJavaClass):
    __javainterfaces__ = ['java/util/ListIterator']
    @java_method('()Ljava/lang/Object;')
    def next(self):
        obj = self.collection.data[self.index]
        self.index += 1
        return obj

Java签名格式


Java签名有一种特殊的格式,一开始可能很难理解。让我们看看细节。签名的格式为:

(<argument1><argument2><...>)<return type>

签名任何部分的所有类型都可以是以下类型之一:


L<java class>; = represent a Java object of the type <java class>

Z = represent a java/lang/Boolean;

B = represent a java/lang/Byte;

C = represent a java/lang/Character;

S = represent a java/lang/Short;

I = represent a java/lang/Integer;

J = represent a java/lang/Long;

F = represent a java/lang/Float;

D = represent a java/lang/Double;

V = represent void, available only for the return type


所有类型都可以具有[前缀以指示数组。返回类型可以是V或空。

(ILjava/util/List;)V
-> argument 1 is an integer
-> argument 2 is a java.util.List object
-> the method doesn't return anything.
(java.util.Collection;[java.lang.Object;)V
-> argument 1 is a Collection
-> argument 2 is an array of Object
-> nothing is returned
([B)Z
-> argument 1 is a Byte []
-> a boolean is returned


在Python中实现Java时,Java方法的签名必须匹配。Java提供了一个名为javap的工具来获取任何Java类的签名。例如:


$ javap -s java.util.Iterator
Compiled from "Iterator.java"
public interface java.util.Iterator{
public abstract boolean hasNext();
  Signature: ()Z
public abstract java.lang.Object next();
  Signature: ()Ljava/lang/Object;
public abstract void remove();
  Signature: ()V
}

JVM选项和类路径


在调用导入JNIU之前需要设置JVM选项,因为它们在VM启动后无法更改。为此,可以:


#antlrtest.py
import jnius_config
jnius_config.add_options('-Xms4096m')
jnius_config.set_classpath('./','./jar_package/antlr-3.5.2-complete.jar')
import jnius

其中 :


jnius_config.add_options():此选项为Jvm参数:


-Xms4096m:初始堆内存4g

-Xmx4096m:最大堆内存4g

-Xmn1024m:年轻代1g

-Xss256K:每个线程占用的空间

-XX:+DisableExplicitGC:禁止显示调用gc

-XX:MaxTenuringThreshold=15:在年轻代存活次数

-XX:+UseParNewGC:对年轻代采用多线程并行回收

-XX:+UseConcMarkSweepGC:年老代采用CMS回收

-XX:+CMSParallelRemarkEnabled:在使用UseParNewGC 的情况下, 尽量减少 mark 的时间

-XX:+UseCMSCompactAtFullCollection:在使用concurrent gc 的情况下, 防止 memoryfragmention, 对live object 进行整理, 使 memory 碎片减少

-XX:LargePageSizeInBytes=128m:指定 Java heap的分页页面大小

-XX:+UseFastAccessorMethods:get,set 方法转成本地代码

-XX:+UseCMSInitiatingOccupancyOnly:指示只有在 oldgeneration 在使用了初始化的比例后concurrent collector 启动收集

-XX:CMSInitiatingOccupancyFraction=70:年老代到达70%进行gc

-Djava.awt.headless=true :Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。

-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/home/gclogs/gc.log:打印日志信息

jnius_config.set_classpath():JAVAclassPATH,路径可为想要运行的所有jar包。


如果使用这些函数设置了类路径,它将覆盖任何类路径环境变量。应将多个选项或路径条目作为多个参数提供给add_和set_函数。如果未提供类路径且未设置类路径,则路径默认为“.”。此功能在Android上不可用。


完整使用案例:


pyjnius库的实际内容没有多少,主要是桥梁作用,这里放上一段使用pyjnius来调用JAVAjar包的实际案例:

#antlrtest.py
import jnius_config
jnius_config.set_classpath('./','./grammar/hive310/antlr-3.5.2-complete.jar')
import jnius
StringStream = jnius.autoclass('org.antlr.runtime.ANTLRStringStream')
Lexer  = jnius.autoclass('grammar.hive310.HiveLexer')
TokenStream  = jnius.autoclass('org.antlr.runtime.CommonTokenStream')
cstream = StringStream("select * from new_table;")
inst = Lexer(cstream)
ts = TokenStream()
ts.setTokenSource(inst)
ts.fill()
jlist = ts.getTokens()
tsize = jlist.size()
for i in range(tsize):
    print(jlist.get(i).getText())

select

 

*

 

from

 

new_table

;

<EOF>

Process finished with exit code 0

目录
相关文章
|
22天前
|
人工智能 安全 Java
Java和Python在企业中的应用情况
Java和Python在企业中的应用情况
46 7
|
5天前
|
XML JSON 数据库
Python的标准库
Python的标准库
116 77
|
19天前
|
机器学习/深度学习 算法 数据挖掘
数据分析的 10 个最佳 Python 库
数据分析的 10 个最佳 Python 库
56 4
数据分析的 10 个最佳 Python 库
|
6天前
|
XML JSON 数据库
Python的标准库
Python的标准库
30 11
|
19天前
|
人工智能 API 开发工具
aisuite:吴恩达发布开源Python库,一个接口调用多个大模型
吴恩达发布的开源Python库aisuite,提供了一个统一的接口来调用多个大型语言模型(LLM)服务。支持包括OpenAI、Anthropic、Azure等在内的11个模型平台,简化了多模型管理和测试的工作,促进了人工智能技术的应用和发展。
74 1
aisuite:吴恩达发布开源Python库,一个接口调用多个大模型
|
6天前
|
数据可视化 Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
通过这些思维导图和分析说明表,您可以更直观地理解和选择适合的数据可视化图表类型,帮助更有效地展示和分析数据。
37 8
|
26天前
|
XML 存储 数据库
Python中的xmltodict库
xmltodict是Python中用于处理XML数据的强大库,可将XML数据与Python字典相互转换,适用于Web服务、配置文件读取及数据转换等场景。通过`parse`和`unparse`函数,轻松实现XML与字典间的转换,支持复杂结构和属性处理,并能有效管理错误。此外,还提供了实战案例,展示如何从XML配置文件中读取数据库连接信息并使用。
Python中的xmltodict库
|
26天前
|
存储 人工智能 搜索推荐
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
Memoripy 是一个 Python 库,用于管理 AI 应用中的上下文感知记忆,支持短期和长期存储,兼容 OpenAI 和 Ollama API。
83 6
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
|
13天前
|
安全 API 文件存储
Yagmail邮件发送库:如何用Python实现自动化邮件营销?
本文详细介绍了如何使用Yagmail库实现自动化邮件营销。Yagmail是一个简洁强大的Python库,能简化邮件发送流程,支持文本、HTML邮件及附件发送,适用于数字营销场景。文章涵盖了Yagmail的基本使用、高级功能、案例分析及最佳实践,帮助读者轻松上手。
25 4
|
22天前
|
Java 程序员 开发工具
在比较Java和Python哪个更易学
在比较Java和Python哪个更易学
31 4