|
下面继续看ListDemo示例。例13.19是原生方法的实现程序。
例13.19 ListImp.c。
1: #include <jni.h>
2: #include "Listdemo.h"
3: #include <stdio.h>
4: struct Nodes{
5: jint value;
6: struct Nodes *next;
7: };
8: static struct Nodes *List;
9:
10: JNIEXPORT void JNICALL Java_ListDemo_createList
11: (JNIEnv *env,jobject obj,jintArray Array){
12: int i;
//得到数组长度
13: jsize len=(*env)->GetArrayLength(env,Array);
//得到数组指针
14: jint *p=(*env)->GetIntArrayElements(env,array,0);
15: struct Nodes *temp;
16: temp=(struct Nodes *)malloc(sizeof(struct Nodes));
//取数组头元素
17: temp->value=p[0];
18: temp->next=NULL;
19: List=temp;
//取数组的元素
20: for(i=1;i<len;i++){
21: temp->text=(struct Nodes*)malloc(sizeof(struct Nodes));
22: temp=temp->next;
23: temp->value=p;
24: temp->next=NULL;
25: }
//释放数组指针
26: (*env)->ReleaseIntArrayElements(env,Array,p,0);
27: }
28: JNIEXPORT void JNICALL
29: Java_ListDemo_showList(JINEnv *env,jobject obj)
30: {
31: struct Nodes *tmp;
32: tmp=List;
33: printf("The content of list:" ;
34: while(tmp!=NULL){
35: printf("%4d",tmp->value);
36: tmp=tmp->next;
37: }
38: }
对比例13.10中的程序,我们可以发现以下几点:
(1)程序引用了jni.h,取代了原先的StubPreamble.h。
(2)函数的原型有变化(这两点在节13.4.1中已述及)。
(3)取数组元素的方法有变化。没有使用unhand操作,代之以JNI提供的函数。
让我们把注意力集中在第三点上。
例子对数组的操作使用了三个函数。它们是:
13:jsize len = (*env)->GetArrayLength(env,Array);
14: jint *p=(*env)->GetIntarrayElements(env,Array,0);
26 *env)->ReleaseIntArrayelements(env,array,p,0);
它们的原型分别为:
☆jsize GetArrayLength(JINEnv *env,jarray array);
☆<指向数组元素的指针>Get<Java基本类型>ArrayElements(JNIEnv *env,jarray array,jboolean *isCopy);
☆void Release <Java基本类型>ArrayElements(JNIEnv *env,jarray array,<指向数组元素的指针>elems,jint mode);
下面分别讲解。
☆jsize GetArrayLength(JNIEnv *env,jarray array);
返回数组元素的个数。env是JNI接口指针,array是数组对象。返回值类型jsize实际是一种无符号整数,取值为地址空间的大小范围。
☆<指向数组元素的指针>Get<Java基本类型>ArrayElements(JNIEnv *env,jarray array,jboolean *isCopy);
这实际上是一族函数,功能是取基本类型(表13.2中的类型,但不包括void)的数组元素,返回值是一个数组(或者说是指针)。从这个原型可以得到诸如GetBooleanArrayElements()、GetShortArrayElements()等函数。参数中的isCopy表明返回的数组指针是指向数据的真正存区(值为1时)还是指向拷贝了数组元素值的另一存区(值为0)。
☆void Release<Java基本类型>ArrayElements(JNIEnv *env,jarray array,<指向数组元素的指针>elems,jint mode);
该函数与上一函数可以说是对应的。它完成的功能是释放资源和数据更新。由于Javar的垃圾收集具有可能改变内存中对象的位置,如不采取必要措施,被访问的数组指针就可能不再指向正确的存区。因此,对于数组,要么把它“钉”在固定的存区,要么把它拷贝至固定的存区,总之在访问它的期间要使数组元素总在原地。作完操作之后,再调用这个函数,解除对它的固定。另外,该函数还反对数组元素的所有屐按程序要求进行更新(在调用这个函数之前,所有更新都没有作用在数组本身上)。参数mode就是决定更新与否的。它取0时,更新数组并释放elems;取JNI——COMMIT时,更新但不释放elems;取JNI——ABORT时,释放elems,不作更新。
对数组的操作是多种多样的。如果数组元素是对象,用上面的函数就不行了,而要用
jobject GetObjectArrayElement(JNIEnv *env,jarray array,jsize index);
得到一个给定元素(index是下标)。如果要改变一个对象数组元素的值,就要用
void SetObjectArrayelement(JNIEnv *env,jarray array,jsize index,jobject value);
如果要创建对象数组,用
jarray NewObjectArray(JNIEnv *env,jsize length,jclass elementClass,jobject initialElement);
其中elementClass是对象的类,initialElement是所有数组元素的初值。创建失败返回NULL。
创建基本类型的数组,用
jarray New<java基本类型>Array(JNIEnv *env,jsize length);
上面讲了访问整个数组的做法,如果数组很大,只需读一个相对较小的数组段,还可以用下面的函数:
void Get<Java基本类型>ArrayRegion(JNIEnv *env,jarray array,jsize start,jsizelen,NativeType *buf);
其中start指明起始位置,len是长度,buf是得到的缓冲区指针,可用于操作数组段中的元素。对应地,有函数
void Set<Java基本类型>ArrayRegion(JNIEnv *env,jarray array,jsize start,jsize len,NativeType *buf);
把缓冲区中的内容拷贝回原数组。
对数组的操作已经介绍完了。最后要注意的是上述函数往往会抛出越界异常,在编程时要加以注意。 |
|