企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
JNI为访问对象数组单独提供了一组函数。GetObjectArrayElement返回指定下表的元素, 而SetObjectArrayElement则修改指定索引上的元素。与基础类型数组不同的是,你不能一次获取或者拷贝对象数组中的所有元素。 字符串和数组是引用类型,你需要使用Get/SetObjectArrayElement来访问字符串数组或者数组的数组。 以下示例代码通过调用原生代码创建了一个int型的二位数组,并打印出这个数组中的所有元素。 ~~~ class ObjectArrayTest { static { System.loadLibrary("ObjectArrayTest"); } private static native int[][] initInt2DArray(int size); public static void main(String[] args) { int[][] i2arr = initInt2DArray(3); for (int i =0; i < 3; ++i) { for (int j = 0; j < 3; j ++) { System.out.print(" " + i2arr[i][j]); } System.out.println(); } } } ~~~ 静态函数initInt2DArray根据给定长度创建了一个二维数组。原生函数负责开辟和初始化这个二维数组,实现如下: ~~~ /* * Class: ObjectArrayTest * Method: initInt2DArray * Signature: (I)[[I */ JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray (JNIEnv * env, jclass cls, jint size) { jobjectArray result; int i; jclass intArrCls = (*env)->FindClass(env, "[I"); if(!intArrCls) { return NULL; /* exception thrown */ } result = (*env)->NewObjectArray(env, size, intArrCls, NULL); if(!result) { return NULL; /* out of memory error thrown */ } for (i = 0; i < size; ++i) { jint tmp[256]; /* make sure it is large enough! */ int j; jintArray iarr = (*env)->NewIntArray(env, size); if(!iarr) { return NULL; } for (j = 0; j < size; j ++) { tmp[j] = i + j; } (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp); (*env)->SetObjectArrayElement(env, result, i, iarr); (*env)->DeleteLocalRef(env, iarr); } return result; } ~~~ >请使用以下命令构建,路径需要修改: >gcc -I/home/wangli/env/jdk8/usr/java/jdk1.8.0_20/include -I/home/wangli/env/jdk8/usr/java/jdk1.8.0_20/include/linux ObjectArrayTest.c -shared -o libObjectArrayTest.so -fPIC -std=c99 newInt2DArray函数首先调用FindClass获取一个二维int数组的类的引用。"[I"参数是int[]类型对应的JNI类描述符,我们会在12.3.2节讲解。如果累加载失败的话,FindClass会返回NULL并抛出异常(比如找不到类文件或者发生了out-of-memory错误)。 接下来使用NewObjectArray函数分配了一个数组,数组中的每一个元素的都是intArrCls对应的类型。NewObjectArray函数仅仅分配二维数组中的第一维,我们还需要填充二维数组的第二维。一个二维数组可以简单的理解为数组的数组。 用于创建二维数组的第二维的代码是非常直接的,NewIntArray分配独立的数组元素,SetIntArrayRegion则复制tmp[]缓冲区中的数据到全新构建的一维数组中去。在完成SetObjectArrayElement调用之后,第i个一维数组中的第j个元素的值是i+j. 运行ObjectArrayTest.main方法,将会产生如下输出: ~~~ 0 1 2 1 2 3 2 3 4 ~~~ 循环最后的DeleteLocalRef函数调用是为了确保虚拟机不会因为需要持有大量像iarr这样的JNI引用而发生out-of-memory异常。在5.2.1章中我们会详细介绍为什么需要使用DeleteLocalRef以及应该在什么时候调用。