【Android应用开发】-(15)JNI----基本数据类型
2012-07-18 07:19
736 查看
前一篇拙文分析JNI的经典实例。这篇拙文将通过实例的方式来简易学习JNI的数据类型。任何语言都有其基本的数据类型,要深入了解,必须要了解最基础的东西,在JNI中,我们会问:Java语言中的数据类型是如何映射到C/C++本地语言中的呢?
目录:
1. 一个简单的实例分析
2. Java与JNI数据类型的映射
3. 字符串的处理
4. 数组的处理
1. 一个简单的实例分析编程中,向函数传参和函数返回值是很普遍的事情,这里就通过几个实例介绍这些技术。先通过一个简单的实例来入门吧。这里扩充HelloWorld.java,先打印一段字符串,然后等待用户输入,看代码:(这里我只列出C的代码)
我们看getLine这个函数接收三个参数JNIEnv,jobject,jstring。其中JNIEnv包括JNI的函数表,如下图:
jobject的意义取决于该方法是静态的还是实例方法,当本地方法作为一个方法时,jobject相当于对象本身,即this。当本地方法作为一个静态方法时,指向所在类。在本实例中,getline是一个本地实例方法实现,所以jobject指向对象本身。
2. 类型的映射
按数据类型来说,java中有两种数据类型,基本的数据类型(int float,char),另一种是引用类型(实例、数组)。在本地方法(native 声明的方法)中声明的参数类型,在JNI中都有对应的类型。
Java与JNI基本类型的映射很直接,请看下表:
除了这些类型之外还定义了jstring,jclass,jobjectArray等结构。他们都继承自jobject.
相比基本类型,对象类型的传递要复杂很多。Java层的对象对象以(opaque references)指针的形势传递到JNI层。opaque references是C的指针类型,它指向JavaVM内部数据结构。使用这种指针的目的是:不希望JNI用户了解J******M内部数据结构。对opaque references所指结构的操作,都要通过JNI方法进行。比如,”java.lang.String”对象,JNI层对于的类型为jstring,对该opaque references的操作要通过JNIEnv->GetStringUTFChars进行。这里需要注意的是:编程的过程中一定要按照原则编程,千万不要为了效率或者容易渠道某个值而绕过JNI,直接操作opaque references。
3. 字符串处理
1) 实例
现在我们回到实例中,看如何处理从java传过去的String类型,请看下面代码?
很抱歉,出错了: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.
这里一定要检测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代码。
在示例代码1中,使用GetIntArrayRegion拷贝数组内容到buf中,这里没有做越界异常检测,因为知道数组有10个,参数3为待拷贝数组的起始位置,参数4为拷贝元素的个数。
JNI支持SetIntArrayRegion允许重新设置数组一个区域的值,其他基本类型(boolean,short, 和float)也有对应的支持。
示例代码2演示通过Get/Release<Type>ArrayElemetns返回Java数组的一个拷贝(实现优良的VM,会返回指向Java数组的一个直接的指针,并标记该内存区域,不允许被GC)。
PS:JNI的内容还是有很多。这两篇JNI主要来自JNI详解,接下来的内容还是看看文档吧。这两篇文章的目的是做一个简单的入门介绍。实践出真知!!
文档下载地址:http://download.csdn.net/detail/tangcheng_ok/4435832
原创文章,转载请注明出处: http://blog.csdn.net/tangcheng_ok
目录:
1. 一个简单的实例分析
2. Java与JNI数据类型的映射
3. 字符串的处理
4. 数组的处理
1. 一个简单的实例分析编程中,向函数传参和函数返回值是很普遍的事情,这里就通过几个实例介绍这些技术。先通过一个简单的实例来入门吧。这里扩充HelloWorld.java,先打印一段字符串,然后等待用户输入,看代码:(这里我只列出C的代码)
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 |
相比基本类型,对象类型的传递要复杂很多。Java层的对象对象以(opaque references)指针的形势传递到JNI层。opaque references是C的指针类型,它指向JavaVM内部数据结构。使用这种指针的目的是:不希望JNI用户了解J******M内部数据结构。对opaque references所指结构的操作,都要通过JNI方法进行。比如,”java.lang.String”对象,JNI层对于的类型为jstring,对该opaque references的操作要通过JNIEnv->GetStringUTFChars进行。这里需要注意的是:编程的过程中一定要按照原则编程,千万不要为了效率或者容易渠道某个值而绕过JNI,直接操作opaque references。
3. 字符串处理
1) 实例
现在我们回到实例中,看如何处理从java传过去的String类型,请看下面代码?
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.
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代码。
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/////////////////////////// jint *carr; jint j, sum1 = 0; carr = (*env)->GetIntArrayElements(env, arr, NULL); if (carr == NULL) { return 0; /* exception occurred */ } for (j = 0; j < 10; j++) { sum1 += carr[j]; } (*env)->ReleaseIntArrayElements(env, arr, carr, 0); return sum1;
在示例代码1中,使用GetIntArrayRegion拷贝数组内容到buf中,这里没有做越界异常检测,因为知道数组有10个,参数3为待拷贝数组的起始位置,参数4为拷贝元素的个数。
JNI支持SetIntArrayRegion允许重新设置数组一个区域的值,其他基本类型(boolean,short, 和float)也有对应的支持。
示例代码2演示通过Get/Release<Type>ArrayElemetns返回Java数组的一个拷贝(实现优良的VM,会返回指向Java数组的一个直接的指针,并标记该内存区域,不允许被GC)。
PS:JNI的内容还是有很多。这两篇JNI主要来自JNI详解,接下来的内容还是看看文档吧。这两篇文章的目的是做一个简单的入门介绍。实践出真知!!
文档下载地址:http://download.csdn.net/detail/tangcheng_ok/4435832
原创文章,转载请注明出处: http://blog.csdn.net/tangcheng_ok
相关文章推荐
- Android JNI入门第五篇——基本数据类型使用
- Android JNI ,jni基本数据类型转换
- Android JNI和NDK学习(08)--JNI实例一 传递基本类型数据
- Unix/Linux C++应用开发-C++变量和基本数据类型
- Android的NDK开发(3)————JNI数据类型的详解
- Android应用开发之使用SharedPreferences存储复杂类型的数据
- Android的NDK开发(3)————JNI数据类型的详解
- Android的jni的调用C,C++的几个应用(基本类型,数组,类(结构体))
- Android JNI编程(二)——C语言的基本数据类型,输出函数,输入函数
- Android的NDK开发(3)————JNI数据类型的详解
- Android的NDK开发(3)————JNI数据类型的详解
- Android jni开发-4(jni基本数据传递)
- Android的NDK开发(3)————JNI数据类型的详解
- Android的NDK开发(3)————JNI数据类型的详解
- Android JNI和NDK学习(08)--JNI实例一 传递基本类型数据
- Android的NDK开发(3)————JNI数据类型的详解
- Android的NDK开发(3)————JNI数据类型的详解
- Android的NDK开发(3)————JNI数据类型的详解
- Android的NDK开发(3)————JNI数据类型的详解
- Android的jni的调用C,C++的几个应用(基本类型,数组,类(结构体))文档-源码