这次来介绍一下,带参数和返回值的jni调用。
因为c的int你无法知道他是多少位的,可能16可能32,当然,在java平台上int总是32位的。基于这个原因,java本地
接口定义了jint、jlong等类型。
boolean = jboolean 字节为1
byte = jbyte 字节为1
char = jchar 字节为2
.....
在
头文件jni.h中,这些类型被typedef语句声明为在目标平台上等价的类型。该头文件也定义了常量JNI_FALSE=0,JNI_TRUE=1。
所以,当你在java层传入的int, long等类型,经过javah的转换,到下面都以
jint,
jlong的形势展现。
这里面,还有一个很常用的类型需要单独考虑,那就是string类型。
在Java中,字符串是
UTF-16编码点的序列,而c的字符串则是以null结尾的字节序列,所以这两种语言中的字符串差别很大。
Java本地接口有两组操作字符串的函数,一组把java字符串转换成“改良的UTF8”字节序列,另一组将
他们转化成UTF-16数值的数组,也就是说转换成jchar数组。
JNI函数有一个有些古怪的调用约定,下面是对NewStringUTF函数的一个调用:
JNIEXPORT jstring JNICALL Java_HelloNative_getGreeting(JNIEnv* env, jclass cl){
jstring jstr;
char greeting[] = "Hello, Native World\n";
jstr = (*env)->NewStringUTF(env, greeting);
return jstr;
}
所有对JNI函数的调用都引用到了env指针,该指针是每一个本地方法的第一个参数。env指针是
函数指针表的指针。所以,你必须在每个JNI调用前面加上
(*env)->,以便实际上取消对函数指针的引用。而且,env是每个JNI函数的第一个参数。
(C++注意: C++中队JNI函数的访问要简单一些。JNIEnv类的C++
版本有一个内敛成员函数,它负责帮你查找函数指针,例如,你可以这样调用NEWStringUTF函数:
jstr = env->NewStringUTF(greeting);
注意,这里从该调用的参数列表里删除了JNIEnv指针。
)
接着string编码来看,两种编码的jstring编码方法,使用两个函数来得到:
NewStringUTF(JNIEnv* env, const char bytes[])和
newString(JNIEnv* env, const jchar chars[], jsize length)。
而
getStringUTF(当然UTF-16对应的是
const jchar* getStringChars()方法,后面的方法就不一一对应了,可以查资料找到)函数可以用来读取一个jstring对象的内容。该
函数返回指向描述字符串的“改良UTF-8”字符的const jbyte*指针。注意,具体的
虚拟机可以自由地选择该编码来表示它内部的字符串,所以,你也许可以得到实际的JAVA字符串的字符指针。因为Java字符串是不可变的,所以慎重处理const很重要,不要试图将数据写到该字符数组中。不过,如果虚拟机使用UTF-16或UTF-32字符作为其内部字符串的表示,那么该函数会分配一个新的
内存块来存储等价的“改良UTF-8”编码字符。
还有一个问题,虚拟机必须知道你何时使用完字符串,这样它就能进行垃圾回收(垃圾回收器是在一个独立
线程中运行的,它能够中断本地方法的执行)。所以,我们必须调用RealeaseStringUTFChars函数。
另外,可以通过调用
GetStringRegion或
GetStringUTFRegion方法来提供你自己的
缓存,来存放字符串的字符。
最后
GetStringUTFLength函数返回编码字符串所需的“改良UTF-8”字符个数。
书上有
例子,有api,网上也能查到,剩下的方法就不多说了,下次分析一下这两个编码方式吧。