JNI在处理基本类型数组和对象数组上面是不同的。对象数组里面是一些指向对象实例或者其它数组的引用。
然后释放所有相关的资源。
基本类型数组:
获取数组元素指针的对应关系:
函数 数组类型 GetBooleanArrayElements boolean GetByteArrayElements byte GetCharArrayElements char GetShortArrayElements short GetIntArrayElements int GetLongArrayElements long GetFloatArrayElements float GetDoubleArrayElements double 释放数组元素指针的对应关系: Function Array Type ReleaseBooleanArrayElements boolean ReleaseByteArrayElements byte ReleaseCharArrayElements char ReleaseShortArrayElements short ReleaseIntArrayElements int ReleaseLongArrayElements long ReleaseFloatArrayElements float ReleaseDoubleArrayElements double数组的引用类型是一般是jarray或者jarray的子类型jintArray。就像jstring不是一个C字符串类型一样,jarray也不是一个C数组类型。
所以,不要直接访问 jarray。你必须使用合适的JNI函数来访问基本数组元素:使用GetIntArrayRegion 函数来把一个 int数组中的所有元素复制到一个C缓冲区中,然后我们在本地代码中通过C缓冲区来访问这些元素。
1 JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) 2 { 3 jint buf[10]; 4 jint i, sum = 0; 5 (*env)->GetIntArrayRegion(env, arr, 0, 10, buf); 6 7 for (i = 0; i < 10; i++) { 8 sum += buf[i]; 9 } 10 return sum; 11 }
JNI支持一系列的Get/Release<Type>ArrayElement 函数,这些函数允许本地代码获取一个指向基本类型数组的元素的指针。
1 JNIEXPORT jint JNICALL Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr) 2 { 3 jint *carr; 4 jint i, sum = 0; 5 carr = (*env)->GetIntArrayElements(env, arr, NULL); //推荐使用 6 if (carr == NULL) { 7 return 0; /* exception occurred */ 8 } 9 for (i=0; i<10; i++) { 10 sum += carr[i]; 11 } 12 (*env)->ReleaseIntArrayElements(env, arr, carr, 0); 13 return sum; 14 }
如果你想在一个预先分配的C缓冲区和内存之间交换数据,应该使用Get/Set</Type>ArrayRegion系列函数。这些函数会进行越界检查,在需要的时候会有可能抛出ArrayIndexOutOfBoundsException异常。
对于少量的、固定大小的数组,Get/Set<Type>ArrayRegion是最好的选择,因为C缓冲区可以在Stack(栈)上被很快地分配,而且复制少量数组元素的代价是很小的。这对函数的另外一个优点就是,允许你通过传入一个索引和长度来实现对子字符串的操作。如果你没有一个预先分配的 C 缓冲区,并且原始数组长度未定,而本地代码又不想在获取数组元素的指针时阻塞的话,使用 Get/ReleasePrimitiveArrayCritical 函数对。就像Get/ReleaseStringCritical函数对一样,这对函数很小心地使用,以避免死锁。
Get/Release<type>ArrayElements 系列函数永远是安全的。JVM 会选择性地返回一个指针,这个指针可能指向原始数据也可能指向原始数据复制。
对象数组:
JNI提供了一个函数对来访问对象数组。GetObjectArrayElement返回数组中指定位置的元素,而SetObjectArrayElement修改数组中指定位置的元素。与基本类型的数组不同的是,你不能一次得到所有的对象元素或者一次复制多个对象元素。字符串和数组都是引用类型,你要使用Get/SetObjectArrayElement来访问字符串数组或者数组的数组。下面的例子调用了一个本地方法来创建一个二维的 int数组,然后打印这个数组的内容:
1 class ObjectArrayTest { 2 private static native int[][] initInt2DArray(int size); 3 public static void main(String[] args) { 4 int[][] i2arr = initInt2DArray(3); 5 for (int i = 0; i < 3; i++) { 6 for (int j = 0; j < 3; j++) { 7 System.out.print(" " + i2arr[i][j]); 8 } 9 System.out.println(); 10 } 11 } 12 static { 13 System.loadLibrary("ObjectArrayTest"); 14 } 15 }
静态本地方法 initInt2DArray 创建了一个给定大小的二维数组。执行分配和初始化数组任务的本地方法可以是下面这样子的:
1 JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env, jclass cls, int size) 2 { 3 jobjectArray result; 4 int i; 5 jclass intArrCls = (*env)->FindClass(env, "[I"); 6 if (intArrCls == NULL) { 7 return NULL; /* exception thrown */ 8 } 9 10 result = (*env)->NewObjectArray(env, size, intArrCls, NULL); //分配第一维11 12 if (result == NULL) { 13 return NULL; /* out of memory error thrown */ 14 } 15 16 for (i = 0; i < size; i++) { 17 jint tmp[256]; /* make sure it is large enough! */ 18 int j; 19 jintArray iarr = (*env)->NewIntArray(env, size); //创建第二维数据20 if (iarr == NULL) { 21 return NULL; /* out of memory error thrown */ 22 } 23 for (j = 0; j < size; j++) { 24 tmp[j] = i + j; 25 } 26 (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); 27 (*env)->SetObjectArrayElement(env, result, i, iarr); 28 (*env)->DeleteLocalRef(env, iarr); 29 } 30 return result; 31 }
转自:
1 Java_com_array_arrayTest_arrayUse( JNIEnv* env,jobject thiz,jobjectArray arrayData) 2 { 3 4 jint i,j; 5 6 int row = (*env)->GetArrayLength(env, arrayData);//获得行数 7 8 jarray myarray = ((*env)->GetObjectArrayElement(env, arrayData, 0)); 9 10 int col =(*env)->GetArrayLength(env, myarray); //获得列数 11 12 jint jniData[row][col]; 13 14 for (i = 0; i < row; i++){ 15 16 myarray = ((*env)->GetObjectArrayElement(env, arrayData, i)); 17 18 jint *coldata = (*env)->GetIntArrayElements(env, (jintArray)myarray, 0 ); 19 20 for (j=0; jReleaseIntArrayElements(env, (jintArray)myarray, coldata,0 ); 25 26 } 27 28 }