可以使用GetFieldID获取一个Java数组变量的ID,然后用GetObjectFiled取得该数组变量到本地方法,返回值为jobject,然后我们可以强制转换为j<Type>Array类型。
可以明白Java的数组,在JNI中都是j<Type>Array的类型。具体的类型如下:如jbooleanArray,jbyteArray等等
- typedef jarray jbooleanArray;
- typedef jarray jbyteArray;
- typedef jarray jcharArray;
- typedef jarray jshortArray;
- typedef jarray jintArray;
- typedef jarray jlongArray;
- typedef jarray jfloatArray;
- typedef jarray jdoubleArray;
- typedef jarray jobjectArray;
j<Type>Array类型是JNI定义的一个对象类型,它并不是C/C++的数组,如int[]数组,double[]数组等等。所以我们要把j<Type>Array类型转换为C/C++中的数组。
JNIEnv定义了一系列的方法来把一个j<Type>Array类型转换为C/C++数组,和把C/C++数组转换为j<Type>Array
- jsize GetArrayLength(jarray array)
-
- jobjectArray NewObjectArray(jsize len, jclass clazz,jobject init)
- jobject GetObjectArrayElement(jobjectArray array, jsize index)
- void SetObjectArrayElement(jobjectArray array, jsize index,jobject val)
-
- jbooleanArray NewBooleanArray(jsize len)
- jbyteArray NewByteArray(jsize len)
- jcharArray NewCharArray(jsize len)
- jshortArray NewShortArray(jsize len)
- jintArray NewIntArray(jsize len)
- jlongArray NewLongArray(jsize len)
- jfloatArray NewFloatArray(jsize len)
- jdoubleArray NewDoubleArray(jsize len)
-
- jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy)
- jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy)
- jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy)
- jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy)
- jint * GetIntArrayElements(jintArray array, jboolean *isCopy)
- jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy)
- jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy)
- jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy)
-
- void ReleaseBooleanArrayElements(jbooleanArray array,jboolean *elems,jint mode)
- void ReleaseByteArrayElements(jbyteArray array,jbyte *elems,jint mode)
- void ReleaseCharArrayElements(jcharArray array,jchar *elems,jint mode)
- void ReleaseShortArrayElements(jshortArray array,jshort *elems,jint mode)
- void ReleaseIntArrayElements(jintArray array,jint *elems,jint mode)
- void ReleaseLongArrayElements(jlongArray array,jlong *elems,jint mode)
- void ReleaseFloatArrayElements(jfloatArray array,jfloat *elems,jint mode)
- void ReleaseDoubleArrayElements(jdoubleArray array,jdouble *elems,jint mode)
-
- void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy)
- void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode)
-
- void GetBooleanArrayRegion(jbooleanArray array,jsize start, jsize len, jboolean *buf)
- void GetByteArrayRegion(jbyteArray array,jsize start, jsize len, jbyte *buf)
- void GetCharArrayRegion(jcharArray array,jsize start, jsize len, jchar *buf)
- void GetShortArrayRegion(jshortArray array,jsize start, jsize len, jshort *buf)
- void GetIntArrayRegion(jintArray array,jsize start, jsize len, jint *buf)
- void GetLongArrayRegion(jlongArray array,jsize start, jsize len, jlong *buf)
- void GetFloatArrayRegion(jfloatArray array,jsize start, jsize len, jfloat *buf)
- void GetDoubleArrayRegion(jdoubleArray array,jsize start, jsize len, jdouble *buf)
-
- void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,const jboolean *buf)
- void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,const jbyte *buf)
- void SetCharArrayRegion(jcharArray array, jsize start, jsize len,const jchar *buf)
- void SetShortArrayRegion(jshortArray array, jsize start, jsize len,const jshort *buf)
- void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint *buf)
- void SetLongArrayRegion(jlongArray array, jsize start, jsize len,const jlong *buf)
- void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,const jfloat *buf)
- void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,const jdouble *buf)
上面是JNIEnv提供的所有操作数组的方法,大致可以分为下面几类。
1、获取数组的长度
- jsize GetArrayLength(jarray array)
不管是基本类型数组,还是对象类型数组
2、对象类型数组的操作
- jobjectArray NewObjectArray(jsize len, jclass clazz,jobject init)
- jobject GetObjectArrayElement(jobjectArray array, jsize index)
- void SetObjectArrayElement(jobjectArray array, jsize index,jobject val)
JNI没有提供直接把Java的对象类型数组(Object[ ])直接转到C++中的jobject[ ]数组的函数。而是直接通过Get/SetObjectArrayElement这样的函数来对Java的Object[ ]数组进行操作
3、基本数据类型数组的操作
基本数据类型数组的操作方法比较多,大致可以分为如下几类:
①、Get<Type>ArrayElements/Realease<Type>ArrayElements
Get<Type>ArrayElements(<Type>Array arr,jboolean* isCopied);
这类函数可以把Java基本类型的数组转换到C/C++中的数组。有两种处理方式,一是拷贝一份传回本地代码,另一个是把指向Java数组的指针直接传回到本地代码,处理完本地化的数组后,通过Realease<Type>ArrayElements来释放数组
Realease<Type>ArrayElements(<Type>Array arr,<Type>* array,jint mode);用这个函数可以选择将如何处理Java跟C/C++的数组,是提交,还是撤销等,内存释放还是不释放
mode可以取下面的值:
0 对Java的数组进行更新并释放C/C++的数组
JNI_COMMIT 对Java的数组进行更新但是不释放C/C++的数组
JNI_ABORT 对Java的数组不进行更新,释放C/C++的数组
②、GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical
void * GetPrimitiveArrayCritical(jarray array, jboolean *isCopy) {
void ReleasePrimitiveArrayCritical(jarray array, void *carray, jint mode)
这两个函数也是JDK1.2 新增的,为了增加直接传回指向Java数组的指针而加入的函数,同样的,也会有用GetStringCritical的死锁的问题。
3、Get<Type>ArrayRegion/Set<Type>ArrayRegion
Get<Type>ArrayRegion(<Type>Array arr,jsize start,jsize len,<Type>* buffer)
在C/C++预先开辟一段内存,然后把Java基本类型的数组拷贝到这段内存中,跟GetStringRegion原理相似。
Set<Type>ArrayRegion(<Type>Array arr,jsize start,jsize len,const <Type>* buffer)
把java基本类型 的数组中的指定范围的元素用C/C++的数组中的元素来赋值
看下面的一个对基本数据类型的操作:
Java端代码如下,有一个本地方法和数组
- package com.tao.test;
-
- public class Test {
- private int [] arrays=new int[]{1,2,3,4,5};
- public native void show();
- static{
- System.loadLibrary("NativeTest");
- }
- public static void main(String[] args) {
- new Test().show();
- }
- }
本地方法:
- JNIEXPORT void JNICALL Java_com_tao_test_Test_show
- (JNIEnv * env, jobject obj)
- {
- jfieldID id_arrsys=env->GetFieldID(env->GetObjectClass(obj),"arrays","[I");
- jintArray arr=(jintArray)(env->GetObjectField(obj,id_arrsys));
- jint* int_arr=env->GetIntArrayElements(arr,NULL);
- jsize len=env->GetArrayLength(arr);
- for(int i=0;i<len;i++)
- {
- cout<<int_arr[i]<<endl;
- }
- env->ReleaseIntArrayElements(arr,int_arr,JNI_ABORT);
- }
最后在Java中调用本地方法,输出了字符串。