一、简单的类型转换本地代码分析
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject this, jstring prompt);
△JNIEXPORT和JNICALL两个宏,确保这个函数在本地库外可见,并且c编译器会进行正确的调用转换。
△方法参数:JNIEnv接口指针,指向一个个函数表,函数表中每一个入口指向一个JNI函数
△方法参数:第二个参数根据本地方法是静态方法还是实例方法而有所不同。
本地方法是静态的:代表本地方法所在的类 ((⊙_⊙)?本地方法c中有类的概念吗)
本地方法是实例方法:代表本地方法所在的对象
△方法参数:jstring是java中传入的参数转换成的本地类型
二、类型的映射
2.1、JNID定义了一个c/c++类型集合,集合中每一个类型对应java的每一个类型
△基本类型:映射是一对一的,int直接对应jint(定义在jint.h中)
△引用类型:当做c指针传递到本地方法中,指针指向JVM中的内部数据结构(内部数据结构在内存中的存储方式是不可见的),
本地代码必须通过JNIEnv中的函数来操作JVM中的对象。如java.lang.String对应的JNI类型是jstring,而本地代码只能通过getStringUTFChars这样的JNI函数来访问字符串中的内容。
△JNI中定义了一个引用对象集合,与java中常用的对象对应,
jobject 是所有引用对象的父类。如jstring, jobjectArray表示对象数组
三、字符串访问
3.1、转化为本地字符串
△jstring类型指向JVM中内部的一个字符串(JVM内部的Unicode字符序列),和常规的C字符串类型*char不同,不能把jstring当做普通的c字符串
△使用JNI中的函数将jstring转换成本地的字符串。JNI支持字符串在
Unicode和UTF-8之间转换
•UTF-8字符串很像NULL结尾的C字符串,包含非ASCII字符时也一样
•UTF-8字符串使用一种向上兼容7-bit ASCII字符串的编码协议。所有7-bit ASCII字符的值都在1~127之间,这些值在UTF-8中保持不变
△exmple:
*char str = (*env)->GetStringUTFChars(env, jstr, 0); //转换成本地类型
if(str == NULL){ //
不要忘记检查,因为JVM需要为新诞生的UTF-8字符串分配内存,有可能因为内存太少而失败
return NULL; //错误时需要
显示调用return,因为异常时
本地方法不会立即返回。异常在调用者中抛出
}
....
(*env)->ReleaseStringUTFChars(env, jstr, str); //需要
显示调用回收内存,否则会造成内存溢出
3.2、构造新的字符串
△通过JNI函数 NewStringUTF 在本地创建新的java.lang.String对象,如果不能分配足够的内存空间,会在调用者中抛出 OutOfMemoryError 异常,并返回 NULL,本地方法立即返回,所以不需要检查返回值
3.3、其他JNI字符串处理函数
△ GetStringChars 和 ReleaseStringChars 获取以Unicode格式编码的字符串 UTF-8字符串以 \0 结尾, Unicode字符串不是 •获取字符串长度: jstring指向Unicode编码的字符串,可以调用 GetStringLength jstring指向UTF-8编码的字符串,可以调用标准C的 strlen 或者不用管编码格式直接调用 GetStringUTFLength