[Android应用开发]-(15)JNI----基本数据类型
这篇拙文将通过实例的方式来简易学习JNI的数据类型。任何语言都有其基本的数据类型,要深入了解,必须要了解最基础的东西,在JNI中,我们会问:Java语言中的数据类型是如何映射到C/C++本地语言中的呢?
目录:
1. 一个简单的实例分析
2. Java与JNI数据类型的映射
3. 字符串的处理
4. 数组的处理
1. 一个简单的实例分析编程中,向函数传参和函数返回值是很普遍的事情,这里就通过几个实例介绍这些技术。先通过一个简单的实例来入门吧。这里扩充HelloWorld.java,先打印一段字符串,然后等待用户输入,看代码:(这里我只列出C的代码)
[cpp]
<SPAN style="FONT-SIZE: 16px"> JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(这串代码怎么来的,请看【Android应用开发】-(14)JNI----经典实例分析 )</SPAN>
JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *, jobject, jstring);//(这串代码怎么来的,请看【Android应用开发】-(14)JNI----经典实例分析 )
我们看getLine这个函数接收三个参数JNIEnv,jobject,jstring。其中JNIEnv包括JNI的函数表,如下图:
jobject的意义取决于该方法是静态的还是实例方法,当本地方法作为一个方法时,jobject相当于对象本身,即this。当本地方法作为一个静态方法时,指向所在类。在本实例中,getline是一个本地实例方法实现,所以jobject指向对象本身。
2. 类型的映射
按数据类型来说,java中有两种数据类型,基本的数据类型(int float,char),另一种是引用类型(实例、数组)。在本地方法(native 声明的方法)中声明的参数类型,在JNI中都有对应的类型。
Java与JNI基本类型的映射很直接,请看下表:
Java
Native(jni.h)
boolean
jboolean
byte
jbyte
char
jchar
short
jshort
Int
jint
long
jlong
Float
jfloat
double
jdouble
除了这些类型之外还定义了jstring,jclass,jobjectArray等结构。他们都继承自jobject.
相比基本类型,对象类型的传递要复杂很多。Java层的对象对象以(opaque references)指针的形势传递到JNI层。opaque references是C的指针类型,它指向JavaVM内部数据结构。使用这种指针的目的是:不希望JNI用户了解JAVAVM内部数据结构。对opaque references所指结构的操作,都要通过JNI方法进行。比如,”java.lang.String”对象,JNI层对于的类型为jstring,对该opaque references的操作要通过JNIEnv->GetStringUTFChars进行。这里需要注意的是:编程的过程中一定要按照原则编程,千万不要为了效率或者容易渠道某个值而绕过JNI,直接操作opaque references。
3. 字符串处理
1) 实例
现在我们回到实例中,看如何处理从java传过去的String类型,请看下面代码?
[cpp]
JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
Printf(“%s”,prompt);
}
JNIEXPORT jstring JNICALL Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
Printf(“%s”,prompt);
}
很抱歉,出错了:incorrect use of jstring as a char* pointer。
这里需要使用对于JNI函数把jstring装好为C/C++字符串。JNI支持Unicode/UTF-8字符编码互转。Unicode 以16-bits值编码;UTF-8是一种以字节为单位变长格式的字符编码,并与7-bits ASCII码兼容。UTF-8字串与C字串一样,以NULL('\0')做结束符, 当UTF-8包含非ASCII 码字符时,以'\0'做结束符的规则不变。7-bit ASCII字符的取值范围在 1-127之间,这些 字符的值域与UTF-8中相同。当最高位被设置时,表示多字节编码。如下,调用GetStringUTFChars,把一个Unicode字串转成UTF-8格式字串,如果你确定字串只包含7-bit ASCII字符。这个字串可以使用C库中的相关函数,如printf.
[cpp]
Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("%s , str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than 127 characters */
scanf("%127s , buf);
return (*env)->NewStringUTF(env, buf);
}
Java_org_winplus_basetype_HelloWorld_getLine (JNIEnv *env, jobject obj, jstring prompt){
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env, prompt, NULL);
if (str == NULL) {
return NULL; /* OutOfMemoryError already thrown */
}
printf("%s , str);
(*env)->ReleaseStringUTFChars(env, prompt, str);
/* We assume here that the user does not type more than 127 characters */
scanf("%127s , buf);
return (*env)->NewStringUTF(env, buf);
}
这里一定要检测GetStringUTFChars的返回值,因为调用该函数会有内存分配操作。失败有该函数返回NULL,并抛出OutOfMemoryError异常。发生异常不会改变代码的执行轨迹,所以当返回Null时要及时处理异常。
1) 释放GetStringUTFChars调用时的内存使用。ReleaseStringUTFChars
2) 构造新的字符串使用JNIEnv->NewStringUTF,同样的,如果没有足够的内存也会抛出OutOfMemoryError异常。
3) 其他字符串操作方法
GetStringChars是有Java 内部Unicode到本地UTF-8的转换函数,可以调用 GetStringLength,获得以Unicode编码的字串长度。也可以使用strlen计算 GetStringUTFChars的返回值,得到字串长度。
const jchar * GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy);
具体的使用请参考JNI详解16-20页
4. 数组的操作
Java部分代码很简单,不贴出来了。我们直接看C代码。
[cpp]
JNIEXPORT jint JNICALL Java_org_winplus_basetype_IntArray_sumArray(JNIEnv *env,
jobject obj, jintArray arr) {
// 我们不能直接这样操作。
/* This program is illegal! */
/*int i, sum = 0;
for (i = 0; i < 10; i++) {
sum += arr[i];
}*/
//////////////////////////////////示例代码1///////////////////////////
// jint buf[10];
// jint i, sum = 0;
// (*env)->GetIntArrayRegion(env, arr, 0, 10, buf);
// for (i = 0; i < 10; i++) {
// sum += buf[i];
// }
// return sum;
///////////////////////////////////示例代码2///////////////////////////&nb
补充:移动开发 , Android ,