博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNI学习4——访问数组(JNI)
阅读量:2042 次
发布时间:2019-04-28

本文共 3803 字,大约阅读时间需要 12 分钟。

JNI在处理基本类型数组和对象数组上面是不同的。对象数组里面是一些指向对象实例或者其它数组的引用。 

基本类型数组:

获取数组元素指针的对应关系:

  函数            数组类型
  GetBooleanArrayElements   boolean
   GetByteArrayElements    byte
  GetCharArrayElements     char
  GetShortArrayElements    short
  GetIntArrayElements     int
   GetLongArrayElements    long
  GetFloatArrayElements     float
  GetDoubleArrayElements   double
  
释放数组元素指针的对应关系:
  Function            ArrayType
   ReleaseBooleanArrayElements  boolean
   ReleaseByteArrayElements    byte
   ReleaseCharArrayElements    char
   ReleaseShortArrayElements    short
   ReleaseIntArrayElements     int
   ReleaseLongArrayElements    long
   ReleaseFloatArrayElements    float
   ReleaseDoubleArrayElements   double

看一个简单的例子。下面的程序调用了一个本地方法 sumArray,这个方法对一个 int数组里面的元素进行累加:

class IntArray {

     private native int sumArray(int[] arr);

     public static void main(String[] args) {

         IntArray p = new IntArray();

         int arr[] = new int[10];

         for (int i = 0; i < 10; i++) {

             arr[i] = i;

         }

         int sum = p.sumArray(arr);

         System.out.println("sum = "+ sum);

     }

     static {

        System.loadLibrary("IntArray");

     }

 }

数组的引用类型是一般是jarray或者jarray的子类型jintArray。就像jstring不是一个C字符串类型一样,jarray也不是一个C数组类型。

所以,不要直接访问 jarray。你必须使用合适的JNI函数来访问基本数组元素:

使用GetIntArrayRegion 函数来把一个 int数组中的所有元素复制到一个C缓冲区中,然后我们在本地代码中通过C缓冲区来访问这些元素。

JNIEXPORT jintJNICALL  Java_IntArray_sumArray(JNIEnv*env, jobject obj, jintArray arr)

{

     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;

}

 

JNI支持一系列的Get/Release<Type>ArrayElement 函数,这些函数允许本地代码获取一个指向基本类型数组的元素的指针。

JNIEXPORT jintJNICALL  Java_IntArray_sumArray(JNIEnv*env, jobject obj, jintArray arr)

 {

     jint *carr;

     jint i, sum = 0;

     carr = (*env)->GetIntArrayElements(env, arr, NULL); //推荐使用

     if (carr == NULL) {

         return 0; /* exception occurred */

     }

     for (i=0; i<10; i++) {

         sum += carr[i];

     }

     (*env)->ReleaseIntArrayElements(env, arr, carr, 0);

     return sum;

 }

如果你想在一个预先分配的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数组,然后打印这个数组的内容:

class 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();

         }

     }

     static {

         System.loadLibrary("ObjectArrayTest");

     }

 }

静态本地方法 initInt2DArray 创建了一个给定大小的二维数组。执行分配和初始化数组任务的本地方法可以是下面这样子的:

JNIEXPORTjobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env, jclasscls, int size)

{

     jobjectArray result;

     int i;

     jclass intArrCls = (*env)->FindClass(env, "[I");

     if (intArrCls == NULL) {

         return NULL; /* exception thrown */

     }

    

     result = (*env)->NewObjectArray(env, size,intArrCls,  NULL); //分配第一维

    

     if (result == NULL) {

         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 == NULL) {

             return NULL; /* out of memory error thrown */

         }

         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;

 } 

转载地址:http://gmnof.baihongyu.com/

你可能感兴趣的文章
Tree UVA - 548 (DFS+建立二叉树)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
(计蒜客) 取石子游戏 (gcd算法灵活运用)
查看>>
Prime Path POJ - 3126 (BFS,素数距离)
查看>>
Wireless Network POJ - 2236 (并查集)
查看>>
【javascript】手写bind函数
查看>>
Kube-state-metrics的collectors配置
查看>>
使用Vmware装虚拟机Ubuntu
查看>>
【java】异常处理及捕获的理解
查看>>
【Java】继承知识点总结
查看>>
【Linux】什么是链接文件及其分类
查看>>
【UML】《Theach yourself uml in 24hours》——hour2&hour3
查看>>
【linux】nohup和&的作用
查看>>
【UML】《Theach yourself uml in 24hours》——hour4
查看>>
僵尸进程产生原因等问题记录
查看>>
【python基础知识】python 2 与python 3 的差异
查看>>
【python基础知识】文件操作中的读写模式
查看>>
css通用button的设置
查看>>
css display属性
查看>>