💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
#### 参考: - 参考网友从国外网站摘抄的[《Java 本地接口规范》](http://blog.csdn.net/zhanghw0917/article/details/7000377) - [百度文库也早已存在,这里下载观看](https://wenku.baidu.com/view/af4a81bafd0a79563c1e728f.html?re=view) - 已整理的目录文档---[Java本地接口规范](http://116.196.111.149:8080/jni.htm)(京东云服务器) #### JNI 数据类型和数据结构 - 基本数据类型 JNI 基本类型和本地等效类型的对应表格如下: ![jni数据类型](https://box.kancloud.cn/32048626f395c65283c639b3bcc15076_757x465.png =757x465) - 引用类型,JNI 还包含了很对对应于不同Java 对象的引用类型,JNI 引用类型的组织层次如下图 ![引用类型](https://box.kancloud.cn/505e7865bc78de34a3f08778fe6e48d8_614x338.png =614x338) #### JNI 接口函数命名方式 - 类型签名 Java 虚拟机的类型签名如下: ![类型签名](https://box.kancloud.cn/39df18c288b8530cd1709e8f5caa9c48_663x385.png =663x385) 例如,Java 方法int feet(int n, String s,int [] arr)的类型签名如下: (ILJava/lang/String;[I)I 圆括号里面为参数,I 表示第一个参数int 型,LJava/lang/String;表示第二个参数为全限定Java.lang.String 类型,[I 表示第三个参数为int 型的数组,圆括号后面为返回值类型,I 表示返回值为int 型。 * 一般函数的JNI 接口函数命名方式 - 一般JNI 接口函数命名如下: Java_包名_类名_方法名。 例如:某工程下com/itheima 包下MainActivity 类的int getIntFromC()方法的C 语言实现函数命名如下: jint Java_com_itheima_MainActivity_getIntFromC(JNIEnv* env,jobject obj) 其中,包名所包含的“/”应全部以下划线替代,其本地实现的参数和返回值也应转换为JNI 类型。 - 重载函数的JNI 接口函数命名方式 - 重载函数的JNI 实现在一般函数的JNI 实现之外,还应添加上类型签名以作为同名函数之间的区别, 其接口函数命名如下:Java_包名_类名_方法名_参数签名。 例如:某工程下com/itheima 包下MainActivity 类的int getIntFromC(int n, String s,int [] arr)方法的C 语言实现函数命名如下: ~~~ jint Java_com_itheima_MainActivity_getIntFromC_ILJava_lang_String_2_3I (JNIEnv* env, jobject obj, jint n, jstring s, jintarray arr)。 ~~~ JNI 在函数命名时采用名字扰乱方案,以保证所有的Unicode 字符都能转换为有效的C 函数名,所有的“/”,无论是包名中的还是全限定类名中的,均使用“_”代替,用_0,„,_9 来代替转义字符,如下: ![转义字符](https://box.kancloud.cn/d1cf220492b90d4317539d320c0f1846_720x165.png =720x165) #### JNI 函数与API - 设置向导三SetUpActivity3.java 的代码逻辑如下所示,设置向导三的图形化界面如2-21 所示。在本文档中我们所主要需要关心的是C/C++数据类型与JNI 本地类型之间的转化过程,这个过程某些数据的转换需要使用JNIEnv 对象的一系列方法来完成。 - 1)jstring 转换为C 风格字符串 `char* test = (char*)(*env)->GetStringUTFChars(env,jstring,NULL);` 使用完毕后,应调用: `(*env)->ReleaseStringUTFChars(env, jstring, test);`释放资源。 - 2)C 风格字符串转换为jstring ~~~ char charStr[50]; jstring jstr; jstr = env -> NewStringUTF(charStr); ~~~ - 3)C 语言中获取的一段char*的buffer 传递给Java 在jni 中new 一个byte 数组,然后使用 `(*env)->SetByteArrayRegion(env, bytearray, 0, len, buffer) `操作将buffer 拷贝到数组中。 这种方式主要是针对buffer 中存在“\0”的情况,如果以C 风格字符串的方式读入,就会损失“\0” 之后的字符。 - 4)数组操作 | JNI 函数 | 功能 | | --- | --- | | GetArrayLength | 返回数组中的元素数 | |NewObjectArray | 创建一个指定长度的原始数据类型数组 | | GetObjectArrayElement | 返回Object 数组的元素 | | SetObjectArrayElement | 设置Object 数组的元素 | | GetObjectArrayRegion | 将原始数据类型数组中的内容拷贝到预先分配好的内存缓存中 | | SetObjectArrayRegion | 设置缓存中数组的值 | | ReleaseObjectArrayRegion | 释放GetObjectArrayRegion 分配的内存 |、 - 对int,char 等基本数据类型的数组操作,将相关Object 名称替换为对应基本数据类型名称即为相关函数。 数组操作的方法选择基于使用者的需求而定,如果使用者需要在内存中拷贝数组并对其进行操作那么我一般使用GetObjectArrayRegion 和SetObjectArrayRegion 函数,否则一般使用SetObjectArrayElement 和GetObjectArrayElement 函数。