JNI简介
JNI(Java Native Interface)是Java编程语言中用于实现Java代码与本地(Native)代码(通常是C或C++代码)交互的机制。它允许Java应用程序调用本地代码中的功能,也可以让本地代码调用Java类和方法。JNI在Java平台上实现了Java与其他编程语言的互操作性。(即可互相调用)
主要目的和用途:
- 访问本地功能: JNI允许Java程序通过调用本地代码来访问底层系统功能、硬件功能或第三方库,这些本地代码通常用C或C++编写。
- 性能优化: 有时候,一些计算密集型任务在本地代码中执行可能比在Java中更高效。通过JNI,你可以将这些任务放在本地代码中,以提高性能。
- 平台特定功能: JNI允许Java程序在需要平台特定功能的情况下,通过本地代码调用这些功能,以适应不同的操作系统和硬件环境。
- 复用现有代码: 如果已经存在C/C++代码库,可以通过JNI将这些库集成到Java应用程序中,而无需重新实现相同的功能。
基本流程:
- 编写本地代码: 首先,你需要编写C/C++代码实现要调用的功能。
- 生成动态库: 将C/C++代码编译成动态链接库(.dll或.so文件),供Java代码调用。
- Java接口定义: 在Java中,你需要编写一个与本地代码对应的JNI接口,这样Java代码就能够调用本地功能。
- 加载本地库: 在Java代码中使用System.loadLibrary("libraryName")加载本地库。
- 调用本地功能: 通过JNI接口调用本地代码,执行相应的功能。
- 资源管理: 注意JNI中需要管理内存和资源,防止内存泄漏和资源泄漏。
需要注意的是,使用JNI涉及到一些底层的编程技巧,以及对内存管理、线程安全等问题的处理。不当的使用可能会导致性能问题和安全隐患。
2 基本概念描述
2.1 基本数据类型
JNI 对于 Java 的基础数据类型(int 等)和引用数据类型(Object、Class、数组等)的处理方式不同。这个原理非常重要,理解这个原理才能理解后面所有 JNI 函数的设计思路:
基础数据类型: 会直接转换为 C/C++ 的基础数据类型,例如 int 类型映射为 jint 类型。由于 jint 是 C/C++ 类型,所以可以直接当作普通 C/C++ 变量使用,而不需要依赖 JNIEnv 环境对象;
引用数据类型: 对象只会转换为一个 C/C++ 指针,例如 Object 类型映射为 jobject 类型。由于指针指向 Java 虚拟机内部的数据结构,所以不可能直接在 C/C++ 代码中操作对象,而是需要依赖 JNIEnv 环境对象。另外,为了避免对象在使用时突然被回收,在本地方法返回前,虚拟机会固定(pin)对象,阻止其 GC。(参考demo中的multipleArray函数实现)
另外需要特别注意一点,基础数据类型在映射时是直接映射,而不会发生数据格式转换。例如,Java char 类型在映射为 jchar 后旧是保持 Java 层的样子,数据长度依旧是 2 个字节,而字符编码依旧是 UNT-16 编码。
以下为Java类型与JNI类型的映射关系表,C++开发人员需要特别注意表中byte与char的区别。
Java类型 | JNI类型 | 描述 | 长度(字节) |
---|---|---|---|
boolean | jboolean | unsinged char | 1 |
byte | jbyte | signed char | 1 |
char | jchar | unsinged short | 2 |
short | jshort | signed short | 2 |
int | jint, jsize | signed int | 4 |
long | jlong | signed long | 8 |
float | jfloat | signed float | 4 |
double | jdouble | signed double | 8 |
Class | jclass | Class类 | / |
String | jstring | 字符串类 | / |
Object | jobject | 所有java类的父类 | / |
Throwable | jthrowable | 异常对象 | / |
boolean[] | jbooleanArray | 布尔数组 | / |
byte[] | jbyteArray | byte数组 | / |
char[] | jcharArray | char数组 | / |
s |