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 层:
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);
}
return objectArray_out;
}
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. JNI 字符串处理函数
GetArrayLength
jsize (GetArrayLength)(JNIEnv env, jarray array);
回来数组中的元素个数
NewObjectArray
jobjectArray NewObjectArray (JNIEnv *env, jsize length, jclass elementClass, jobject initialElement);
构建 JNI 引证类型的数组,它将保存类 elementClass 中的目标。所有元素初始值均设为 initialElement,一般运用 NULL 就好。假如系统内存不足,则抛出 OutOfMemoryError 反常
GetObjectArrayElement和SetObjectArrayElement
jobject GetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index)
回来 jobjectArray 数组的元素,通常是获取 JNI 引证类型数组元素。假如 index 不是数组中的有用下标,则抛出 ArrayIndexOutOfBoundsException 反常。
void SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index, jobject value)
设置 jobjectArray 数组中 index 下标目标的值。假如 index 不是数组中的有用下标,则会抛出 ArrayIndexOutOfBoundsException 反常。假如 value 的类不是数组元素类的子类,则抛出 ArrayStoreException 反常。
New<PrimitiveType>Array 函数集
NativeTypeArray New<PrimitiveType>Array (JNIEnv* env, jsize size)
用于构造 JNI 根本类型数组目标。
在实践应用中把 PrimitiveType 替换为某个实践的根本类型数据类型,然后再将 NativeType 替换成对应的 JNI Native Type 即可,详细的:
函数名 回来类型
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshorArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray
Get/ReleaseArrayElements函数集
NativeType* Get<PrimitiveType>ArrayElements(JNIEnv *env, NativeTypeArray array, jboolean *isCopy)
该函数用于将 JNI 数组类型转化为 JNI 根本数据类型数组,在实践运用过程中将 PrimitiveType 替换成某个实践的根本类型元素拜访函数,然后再将NativeType替换成对应的 JNI Native Type 即可:
函数名 转化前类型 转化后类型
GetBooleanArrayElements() jbooleanArray jboolean*
GetByteArrayElements() jbyteArray jbyte*
GetCharArrayElements() jcharArray jchar*
GetShortArrayElements() jshortArray jshort*
GetIntArrayElements() jintArray jint*
GetLongArrayElements() jlongArray jlong*
GetFloatArrayElements() jfloatArray jfloat*
GetDoubleArrayElements() jdoubleArray jdouble*
void Release<PrimitiveType>ArrayElements (JNIEnv *env, NativeTypeArray array, NativeType *elems,jint mode);
该函数用于通知 JVM,数组不再运用,能够清理先关内存了。在实践运用过程中将 PrimitiveType 替换成某个实践的根本类型元素拜访函数,然后再将 NativeType 替换成对应的 JNI Native Type 即可:
函数名 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
void Set<PrimitiveType>ArrayRegion (JNIEnv *env, NativeTypeArray array, jsize start, jsize len, NativeType *buf);
该函数用于将根本类型数组某一区域复制到 JNI 数组类型中。在实践运用过程中将 PrimitiveType 替换成某个实践的根本类型元素拜访函数,然后再将 NativeType 替换成对应的 JNI Native Type 即可:
函数名 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
关于
我叫阿豪,2015 年本科毕业于国防科技大学指挥自动化专业,毕业后,从事信息化装备的研制作业。主要研讨方向为 Android Framework 与 Linux Kernel,2023年春节后开始做 Android Framework 相关的技能共享。
假如你对 Framework 感兴趣或许正在学习 Framework,能够参阅我总结的Android Framework 学习道路攻略,也可重视我的微信大众号,我会在大众号上持续共享我的经历,协助正在学习的你少走一些弯路。学习过程中假如你有疑问或许你的经历想要共享给大家能够增加我的微信,我拉你进技能交流群。