购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.5 JNI机制

JNI(Java Native Interface)是一种外部函数接口编程框架,让开发人员能够编写本地方法(C/C++函数)来处理无法完全用Java编写应用程序的情况。例如,当标准Java类库不支持特定于平台的特性或程序库时,可以用JNI的方式来调用自定义函数进行处理。JDK中的很多系统方法都是采用JNI实现的,例如System.out.print方法。JNI一开始是为了C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定的函数库就可以了。JNI机制如图2-15所示。

图2-15 JNI机制

本地代码(C/C++函数)与JVM之间是通过JNI接口实现交互的。JNI函数通过接口指针来获得本地方法,本地方法将JNI接口指针当作参数来接收。JVM保证在从相同的Java线程中对本地方法进行多次调用时,传递给本地方法的接口指针是相同的,本地方法被不同的Java线程调用时,也可使用不同的JNI接口指针。JNI与操作系统本地编译的动态链接库进行的这种交互,会严重影响Java平台的可移植性。这种兼容性问题可以通过在不同的操作系统上提供不同的动态链接库来解决,如图2-16所示。

图2-16 JNI编译动态链接库

例如:在Windows平台下,本地方法会编译为.dll文件;在Linux平台下,本地方法会编译为.so文件;在Mac下,本地方法会编译为.jnilib文件。而不同平台下的JVM会按照约定加载固定类型的动态链接库文件,使得JNI的功能可以被正常地调用。

2.5.1 JNI开发流程

JNI的开发流程如图2-17所示。

1)需要在Java代码中声明一个本地方法,这个方法不用进行具体的实现,然后用javac编译器将Java代码编译成.class文件。

2)用javah-jni来生成对应的C语言的头文件,头文件中有本地方法的声明。

3)根据头文件来实现C语言的逻辑,并编译成动态链接库。

4)在本地方法运行的时候,先完成动态链接库的代码加载,然后就可以调用对应方法来访问C语言的实现了。

图2-17 JNI开发流程

2.5.2 JNI数据类型转换

众所周知,Java的数据类型是与C/C++的数据类型是完全不一样的,而JNI是处于Java和本地库(C/C++语言实现)的中间层,JNI对两种不同的数据类型之间必须进行适配转换,所以在JNI与Java之间就会有数据类型的对应关系。

1.基本数据类型的转换

JNI首先定义基础数据类型的关系,每种数据类型都有一个独立的JNI字符签名来表示。例如Java语言的int类型,JNI中对应的类型是jint,C++语言中对应的类型是int或long。从转换表中可以看出,int的签名是I。大多字符都符合常规的认知,但boolean对应的签名是Z,long对应的签名是J,这个需要特别注意。JNI基础数据类型的详细信息如图2-18所示。

图2-18 JNI基础数据类型映射

2.引用类型的转换

对引用类型的数据对象,JNI也实现了数据类型映射。首先是对String与Throwable进行了单独的类型签名,String对应的是“Ljava/lang/String”;标识。因为String使用频率较高,所以在JNI中单独创建了一个jstring类型。除了Class、String、Throwable和基本数据类型的数组外,其余所有Java对象的数据类型在JNI中都用jobject表示。所有数组的表示都是以“[”开头,后面加上对应的数据类型。JNI引用数据类型的详细信息如图2-19所示。

图2-19 JNI引用数据类型映射

3.方法签名

JVM需要通过JNI的描述来找到对应的C++的实现函数,理论上仅通过方法名称就可以实现。但是因为Java类的方法是可以重载的,重载的方法名虽相同,但参数是不一样的,所以JNI无法仅通过方法名确定对应的是Java里面的哪个方法,必须结合参数签名一起来完成方法的定位。JNI定义了本地方法的签名规则,如代码清单2-1所示。

代码清单2-1 方法签名

每个参数用数据类型标识,多个参数之间是没有分隔符号的,这个和我们的常识有点差别,需要特别注意。所有的参数都在小括号里面。参数后面就是返回类型,参数和返回类型是没有空格的。

2.5.3 实现案例

System类是Java最常用的类,其中currentTimeMillis方法与nanoTime方法是我们经常获取时间的两种方法。arraycopy方法是用来进行数组内容复制的。下面是System类的Java源代码,可以清楚地看到,三个方法都被native关键字标识为本地方法,System类的native方法描述如代码清单2-2所示。

代码清单2-2 System类native方法描述

在JVM的System.c文件里面声明了System类对应的JNI方法映射关系,如代码清单2-3所示。

代码清单2-3 JNI方法映射关系

第1列表示的是Java的方法名称,第2列是方法的描述符,第3列对应的是C语言函数的实现。从currentTimeMillis的描述符可以清晰地看到,方法没有入参,返回的类型是long。从arraycopy的方法描述符可以看出,方法有5个输入参数:第1个是Object对象,第2个是int类型参数,第3个是Object对象,第4个与第5个都是int类型参数。 ykcCmPYO7Y3GCEURGIIJHRYoA7TILuoLclhjQZHlAOheMg715twFmEg0smQt0yn3

点击中间区域
呼出菜单
上一章
目录
下一章
×