JNI 访问Java数组

JNI 访问Java数组

 

本文将介绍JNI如何访问基本类型数组、对象数组(包括字符串数组)以及二维数组。可以使用GetArrayLength来获取数组的长度,使用GetIntArrayElements等函数直接访问基本类型数组中的元素,使用GetObjectArrayElement等函数访问对象数组和字符串数组,使用过程中确保类型匹配。

1、引子

JNI 中的数组分为基本类型数组和对象数组,它们的处理方式是不一样的,基本类型数组中的所有元素都是 JNI 的基本数据类型,可以直接访问。而对象数组中的所有元素是一个类的实例或其它数组的引用,和字符串操作一样,不能直接访问 Java 传递给 JNI 层的数组,必须选择合适的 JNI 函数来访问和设置Java层的数组对象。

2、数组访问

2.1 基本类型数组

Java 层:

private native double[] sumAndAverage(int[] numbers);

JNI 层:

复制代码
JNIEXPORT jdoubleArray JNICALL Java_HelloJNI_sumAndAverage(JNIEnv *env, jobject obj, jintArray inJNIArray) {
    //类型转换 jintArray -> jint*
    jboolean isCopy;
    jint* inArray = env->GetIntArrayElements(inJNIArray, &isCopy);
 
    if (JNI_TRUE == isCopy) {
        cout << "C 层的数组是 java 层数组的一份拷贝" << endl;
    } else {
        cout << "C 层的数组指向 java 层的数组" << endl;
    }
 
    if(nullptr == inArray) return nullptr;
    //获取到数组长度
    jsize length = env->GetArrayLength(inJNIArray);
 
    jint sum = 0;
    for(int i = 0; i < length; ++i) {
        sum += inArray[i];
    }
 
    jdouble average = (jdouble)sum / length;
    //释放数组
    env->ReleaseIntArrayElements(inJNIArray, inArray, 0); // release resource
 
    //构造返回数据,outArray 是指针类型,需要 free 或者 delete 吗?要的
    jdouble outArray[] = {sum, average};
    jdoubleArray outJNIArray = env->NewDoubleArray(2);
    if(NULL == outJNIArray) return NULL;
    //向 jdoubleArray 写入数据
    env->SetDoubleArrayRegion(outJNIArray, 0, 2, outArray);
    return outJNIArray;
}
复制代码

2.2 引用类型数组

Java 层:

public native String[] operateStringArrray(String[] array);

JNI 层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
JNIEXPORT jobjectArray JNICALL Java_com_xxx_jni_JNIArrayManager_operateStringArrray
  (JNIEnv * env, jobject object, jobjectArray objectArray_in)
{
    //获取到长度信息
    jsize  size = env->GetArrayLength(objectArray_in);
  
   /*******获取从JNI传过来的String数组数据**********/
  
   for(int i = 0; i < size; i++)
   {
      jstring string_in= (jstring)env->GetObjectArrayElement(objectArray_in, i);
        char *char_in  = env->GetStringUTFChars(str, nullptr);
   }
  
   /***********从JNI返回String数组给Java层**************/
   jclass clazz = env->FindClass("java/lang/String");
   jobjectArray objectArray_out;
   const int len_out = 5;
   objectArray_out = env->NewObjectArray(len_out, clazz, NULL);
   char * char_out[]=  { "Hello,", "world!", "JNI", "is", "fun" };
  
   jstring temp_string;
   for( int i= 0; i < len_out; i++ )
    {  
        temp_string = env->NewStringUTF(char_out[i]);
        env->SetObjectArrayElement(objectArray_out, i, temp_string);
    }<br>
   return objectArray_out;
}

对于对象数组,也就是引用类型数组,数组中的每个类型都是引用类型,JNI 只提供了如下函数来操作:

  • GetObjectArrayElement
  • SetObjectArrayElement

和基本数据类型不同的是,不能一次得到数据中的所有对象元素或者一次复制多个对象元素到缓冲区。只能通过上面的函数来访问或者修改指定位置的元素内容。

2.3 二维数组

Java 层:

public native int[][] operateTwoIntDimArray(int[][] array_in);

JNI 层:

复制代码
JNIEXPORT jobjectArray JNICALL Java_com_xxx_jni_JNIArrayManager_operateTwoIntDimArray(JNIEnv * env, jobject object, jobjectArray objectArray_in)
{
   /********** 解析从Java得到的int型二维数组 **********/
   int i, j ;
   const int row = env->GetArrayLength(objectArray_in);//获取二维数组的行数
   jarray array = (jarray)env->GetObjectArrayElement(objectArray_in, 0);
   const int col = env->GetArrayLength(array);//获取二维数组每行的列数
 
   //根据行数和列数创建int型二维数组
   jint intDimArrayIn[row][col];
 
   for(i =0; i < row; i++)
   {
     array
= (jintArray)env->GetObjectArrayElement(objectArray_in, i);    //操作方式一,这种方法会申请natvie memory内存    jint *coldata = env->GetIntArrayElements((jintArray)array, NULL );   for (j=0; j<col; j++) {     intDimArrayIn [i] [j] = coldata[j]; //取出JAVA类中int二维数组的数据,并赋值给JNI中的数组   }    //操作方式二,赋值,这种方法不会申请内存    // env->GetIntArrayRegion((jintArray)array, 0, col, (jint*)&intDimArrayIn[i]);
      env
->ReleaseIntArrayElements((jintArray)array, coldata,0 );   }   /**************创建一个int型二维数组返回给Java**************/   const int row_out = 2;//行数   const int col_out = 2;//列数   //获取数组的class   jclass clazz = env->FindClass("[I");//一维数组的类   //新建object数组,里面是int[]   jobjectArray intDimArrayOut = env->NewObjectArray(row_out, clazz, NULL);   int tmp_array[row_out][col_out] = {{0,1}, {2,3}};   for(i = 0; i< row_out; i ++)   {     jintArray intArray = env->NewIntArray(col_out);     env->SetIntArrayRegion(intArray, 0, col_out, (jint*)&tmp_array[i]);     env->SetObjectArrayElement(intDimArrayOut, i, intArray);   }
  
return intDimArrayOut; }
复制代码

3、小结

GetArrayLength :返回数组中的元素个数

jsize (GetArrayLength)(JNIEnv env, jarray array);

 

NewObjectArray :构建 JNI 引用类型的数组,它将保存类 elementClass 中的对象。所有元素初始值均设为 initialElement,一般使用 NULL 就好。如果系统内存不足,则抛出 OutOfMemoryError 异常

jobjectArray NewObjectArray (JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);

 

GetObjectArrayElement :返回 jobjectArray 数组的元素,通常是获取 JNI 引用类型数组元素。如果 index 不是数组中的有效下标,则抛出 ArrayIndexOutOfBoundsException 异常

jobject GetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index);

 

SetObjectArrayElement :设置 jobjectArray 数组中 index 下标对象的值。如果 index 不是数组中的有效下标,则会抛出 ArrayIndexOutOfBoundsException 异常。如果 value 的类不是数组元素类的子类,则抛出 ArrayStoreException 异常。

void SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index, jobject value);

 

New<PrimitiveType>Array 函数集:用于构造 JNI 基本类型数组对象。在实际应用中把 PrimitiveType 替换为某个实际的基本类型数据类型,然后再将 NativeType 替换成对应的 JNI Native Type 即可,具体的:

NativeTypeArray New<PrimitiveType>Array (JNIEnv* env, jsize size)
1
2
3
4
5
6
7
8
9
函数名                      返回类型
NewBooleanArray()           jbooleanArray
NewByteArray()              jbyteArray
NewCharArray()              jcharArray
NewShortArray()             jshorArray
NewIntArray()               jintArray
NewLongArray()              jlongArray
NewFloatArray()             jfloatArray
NewDoubleArray()            jdoubleArray     

 

Get<PrimitiveType>ArrayElements函数集:该函数用于将 JNI 数组类型转换为 JNI 基本数据类型数组,在实际使用过程中将 PrimitiveType 替换成某个实际的基本类型元素访问函数,然后再将NativeType替换成对应的 JNI Native Type 即可:

NativeType* Get<PrimitiveType>ArrayElements(JNIEnv *env, NativeTypeArray array, jboolean *isCopy)
复制代码
函数名                           转换前类型             转换后类型
GetBooleanArrayElements()       jbooleanArray          jboolean*
GetByteArrayElements()          jbyteArray             jbyte*
GetCharArrayElements()          jcharArray             jchar*
GetShortArrayElements()         jshortArray            jshort*
GetIntArrayElements()           jintArray              jint*
GetLongArrayElements()          jlongArray             jlong*
GetFloatArrayElements()         jfloatArray            jfloat*
GetDoubleArrayElements()        jdoubleArray           jdouble*
复制代码

 

Release<PrimitiveType>ArrayElements函数集:该函数用于通知 JVM,数组不再使用,可以清理先关内存了。在实际使用过程中将 PrimitiveType 替换成某个实际的基本类型元素访问函数,然后再将 NativeType 替换成对应的 JNI Native Type 即可:

void Release<PrimitiveType>ArrayElements (JNIEnv *env, NativeTypeArray array, NativeType *elems,jint mode);
复制代码
函数名                              NativeTypeArray        NativeType
ReleaseBooleanArrayElements()       jbooleanArray          jboolean
ReleaseByteArrayElements()          jbyteArray             jbyte
ReleaseCharArrayElements()          jcharArray             jchar
ReleaseShortArrayElements()         jshortArray            jshort
ReleaseIntArrayElements()           jintArray              jint
ReleaseLongArrayElements()          jlongArray             jlong
ReleaseFloatArrayElements()         jfloatArray            jfloat
ReleaseDoubleArrayElements()        jdoubleArray           jdouble
复制代码

 

Get/Set<PrimitiveType>ArrayRegion :该函数用于将基本类型数组某一区域复制到 JNI 数组类型中。在实际使用过程中将 PrimitiveType 替换成某个实际的基本类型元素访问函数,然后再将 NativeType 替换成对应的 JNI Native Type 即可:

void Set<PrimitiveType>ArrayRegion (JNIEnv *env, NativeTypeArray array, jsize start, jsize len, NativeType *buf);
复制代码
函数名                              NativeTypeArray        NativeType
SetBooleanArrayRegion()             jbooleanArray          jboolean
SetByteArrayRegion()                jbyteArray             jbyte
SetCharArrayRegion()                jcharArray             jchar
SetShortArrayRegion()               jshortArray            jshort
SetIntArrayRegion()                 jintArray              jint
SetLongArrayRegion()                jlongArray             jlong
SetFloatArrayRegion()               jfloatArray            jfloat
SetDoubleArrayRegion()              jdoubleArray           jdouble
复制代码

 

参考自:https://blog.csdn.net/chuyouyinghe/article/details/131241999

 

posted @ 2025-08-15 18:50  tomato-haha  阅读(5)  评论(0)    收藏  举报