博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JNI——访问数组
阅读量:5957 次
发布时间:2019-06-19

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

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

因为速度的原因,先通过GetXXXArrayElements函数把简单类型的数组转化成本地类型的数组,并返回其数组的指针,然后通过该指针来对拷贝数组进行处理。
对拷贝数组处理完后,通过ReleaseXXXArrayElements函数把修改后的拷贝数组的反射到java数组,

然后释放所有相关的资源。

基本类型数组:

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

  函数            数组类型
  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; j
ReleaseIntArrayElements(env, (jintArray)myarray, coldata,0 ); 25 26 } 27 28 }

 

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

你可能感兴趣的文章
几种排序算法及 Python 实现
查看>>
java后端的学习之路(一) ------ mysql和jdbc&DBUtils
查看>>
(LeetCode-数组-2) 只出现一次的数字
查看>>
基于Nginx的中间件架构(三):Rewrite规则、secure_link和Geoip读取地域信息模块、HTTPS服务...
查看>>
CSS引入外部字体方法,附可用demo
查看>>
窥探React - 源码分析
查看>>
HTML之基础介绍
查看>>
puppeteer_node爬虫分布式进阶
查看>>
Phoenix报错(2-2)AccessDeniedException: Insufficient permissions
查看>>
leetcode 605 Can Place Flowers
查看>>
JS 单例模式
查看>>
解决oninput事件在中文输入法下会取得拼音的值的问题
查看>>
Hooking & Executing Code with dlopen & dlsym -- C functions
查看>>
GitLab 安装笔记
查看>>
JavaScript 异步队列及Co实现
查看>>
原生javascript实现无缝滚动
查看>>
EventBus使用方法详解
查看>>
使用 Phoenix-4.11.0连接 Hbase 集群 ,并使用 JDBC 查询测试
查看>>
判断字符串是否含有中英文和数字
查看>>
javascript模拟原生Promise语法
查看>>