您的位置:首页 > 移动开发 > Android开发

【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的代码)
  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用户了解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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: