JNI中參數的傳遞與操作(中)

三、數組
JNI提供了對Java數組進行操作的功能。
它提供了兩類函數:一類用於操作java的簡單型數組,另一類用於是操作對象類型數組的。
簡單數組
因爲速度的原因,先通過GetXXXArrayElements函數把簡單類型的數組轉化成本地類型的數組,並返回其數組的指針,然後通過該指針來對拷貝數組進行處理。
對拷貝數組處理完後,通過ReleaseXXXArrayElements函數把修改後的拷貝數組的反射到java數組,
然後釋放所有相關的資源。
注意:GetXXXArrayElements函數(見表B)中,XXX代表了數組的類型。這種函數把Java數組看成參數,返回一個指向對應的本地類型的數組的指針
表B

函數

Java數組本地C/C++類型

Java本地C/C++類型

GetBooleanArrayElements

jbooleanArray

Jboolean

GetByteArrayElements

jbyteArray

Jbyte

GetCharArrayElements

jcharArray

Jchar

GetShortArrayElements

jshortArray

Jshort

GetIntArrayElements

jintArray

Jint

GetLongArrayElements

jlongArray

Jlong

GetFloatArrayElements

jfloatArray

Jfloat

GetDoubleArrayElements

jdoubleArray

Jdouble

GetXXXArrayElements系列函數如下
  jboolean * GetBooleanArrayElements (jbooleanArray val0, jboolean * val1)
  jbyte * GetByteArrayElements (jbyteArray val0, jboolean * val1)
  jchar * GetCharArrayElements (jcharArray val0, jboolean * val1)
  jshort * GetShortArrayElements (jshortArray val0, jboolean * val1)
  jint * GetIntArrayElements (jintArray val0, jboolean * val1)
  jlong * GetLongArrayElements (jlongArray val0, jboolean * val1)
  jfloat * GetFloatArrayElements (jfloatArray val0, jboolean * val1)
  jdouble * GetDoubleArrayElements (jdoubleArray val0, jboolean * val1)
第一個參數,val0是你要操作的數組。
第二參數,val1什麼意思呢?不知道。一般用0就可以。
ReleaseXXXAarryElements系列函數如下
  void ReleaseBooleanArrayElements (jbooleanArray val0, jboolean * val1, jint val2)
  void ReleaseByteArrayElements (jbyteArray val0, jbyte * val1, jint val2)
  void ReleaseCharArrayElements (jcharArray val0, jchar * val1, jint val2)
  void ReleaseShortArrayElements (jshortArray val0, jshort * val1, jint val2)
  void ReleaseIntArrayElements (jintArray val0, jint * val1, jint val2)
  void ReleaseLongArrayElements (jlongArray val0, jlong * val1, jint val2)
  void ReleaseFloatArrayElements (jfloatArray val0, jfloat * val1, jint val2)
  void ReleaseDoubleArrayElements (jdoubleArray val0, jdouble * val1, jint val2)
參數意義
把數組val0從第0個開始的val2個元素設置爲val1地址開始的val2個元素的值
如果想返回一個新的數組,可以先用NewXXXArray函數創建一個Java數組本地C/C++類型數組,然後通過ReleaseXXXAarryElements/SetXXXArrayRegion函數設置數組值,最後返回直接返回該數組就可以了。
另外我們還可以用GetXXXArrayRegion函數取得數組某段的數據。這來的XXX表示是什麼類型的簡單數組
NewXXXArray系列函數如下:
  jbooleanArray NewBooleanArray (jsize val0)
  jbyteArray NewByteArray (jsize val0)
  jcharArray NewCharArray (jsize val0)
  jshortArray NewShortArray (jsize val0)
  jintArray NewIntArray (jsize val0)
  jlongArray NewLongArray (jsize val0)
  jfloatArray NewFloatArray (jsize val0)
  jdoubleArray NewDoubleArray (jsize val0)
 第一參數,jsize val0表示要創建的數組的大小.
SetXXXArrayRegion系列函數如下:
  void SetBooleanArrayRegion (jbooleanArray val0, jsize val1, jsize val2, jboolean * val3)
  void SetByteArrayRegion (jbyteArray val0, jsize val1, jsize val2, jbyte * val3)
  void SetCharArrayRegion (jcharArray val0, jsize val1, jsize val2, jchar * val3)
  void SetShortArrayRegion (jshortArray val0, jsize val1, jsize val2, jshort * val3)
  void SetIntArrayRegion (jintArray val0, jsize val1, jsize val2, jint * val3)
  void SetLongArrayRegion (jlongArray val0, jsize val1, jsize val2, jlong * val3)
  void SetFloatArrayRegion (jfloatArray val0, jsize val1, jsize val2, jfloat * val3)
  void SetDoubleArrayRegion (jdoubleArray val0, jsize val1, jsize val2, jdouble * val3)
參數的意義
表示把數組val0從val1開始的val2個元素設置爲val3內存地址開始的val2個元素
GetXXXArrayRegion系列函數如下
  void GetBooleanArrayRegion (jbooleanArray val0, jsize val1, jsize val2, jboolean * val3)
  void GetByteArrayRegion (jbyteArray val0, jsize val1, jsize val2, jbyte * val3)
  void GetCharArrayRegion (jcharArray val0, jsize val1, jsize val2, jchar * val3)
  void GetShortArrayRegion (jshortArray val0, jsize val1, jsize val2, jshort * val3)
  void GetIntArrayRegion (jintArray val0, jsize val1, jsize val2, jint * val3)
  void GetLongArrayRegion (jlongArray val0, jsize val1, jsize val2, jlong * val3)
  void GetFloatArrayRegion (jfloatArray val0, jsize val1, jsize val2, jfloat * val3)
  void GetDoubleArrayRegion (jdoubleArray val0, jsize val1, jsize val2, jdouble * val3)
參數的意義
表示把數組val1從第val個元素開始的val2個元素拷貝到val3地址所指向的內存區域
對象數組
如果你需要對java對象數組的對象進行操作,你必須使用GetObjectArrayElement函數以jobject形式返回數組的元素,然後再操作jobject
你也可以用SetObjectArrayElement函數把jobject放進java對象數組,另外GetArrayLength函數能返回數組的長度。
關於對jobject的操作請參照後文。
如果想返回一個新的數組,可以先用NewObjectArray函數創建一個Java數組本地C/C++類型對象數組,然後通過SetObjectArrayElement函數設置數組元素(java對象),最後返回直接返回該數組就可以了。
關於如何創建在JNI中創建一個jobject(Java對象)請參照後文。
 jarray NewObjectArray (jsize val0, jclass cl1, jobject obj2)
第一參數,val0表示要創建的對象數組的大下。
第二參數,cl1表示創建的對象數組的元素是什麼類型.
第三個參數,obj2表示數組元素的默認對象,一般用0表示null
 jobject GetObjectArrayElement (jobjectArray val0, jsize val1)
參數意義
表示取得val0數組的第val1個元素
 void SetObjectArrayElement (jobjectArray val0, jsize val1, jobject obj2)
參數意義
表示把val0數組的第val1個元素設置爲對象obj2
另外,String數組當做一般的對象數組處理就可以了,只是String比普通的對象多了一些操作接口。
其實jstring只是jobject的一個子類,參看jni.h可知:
struct __jobject {};
struct __jclass : __jobject {};
struct __jstring : __jobject {};
示例
JNIEXPORT jobjectArray JNICALL Java_com_robin_HelloActivity_getStringArrayFromJni
(JNIEnv *env, jobject thiz)
{
    jstring      str;
    jobjectArray args = 0;
    jsize        len = 5;
    char*        sa[] = { "Hello,", "world!", "This", "is", "robin" };
    int          i=0;
    args = (env)->NewObjectArray(len,(env)->FindClass("java/lang/String"),0);
    for( i=0; i < len; i++ )
    {
        str = (env)->NewStringUTF(sa[i] );
        (env)->SetObjectArrayElement(args, i, str);
    }
    return args;
}

二維數組和String數組

在JNI中,二維數組和String數組都被視爲object數組,因爲數組和String被視爲object。仍然用一個例子來說明,這次是一個二維int數組,作爲返回值。

JNIEXPORT jobjectArray JNICALL Java_ObjectArrayTest_initInt2DArray(JNIEnv *env, jclass cls, int size)  
{  
    jobjectArray result;  
    jclass intArrCls = env->FindClass("[I");  
    result = env->NewObjectArray(size, intArrCls, NULL); //爲result分配空間   
    for (int i = 0; i < size; i++) {  
        jint tmp[256]; /* make sure it is large enough! */  
        jintArray iarr = env->NewIntArray(size);      //爲一維int數組iarr分配空間
        for(int j = 0; j < size; j++) {  
            tmp[j] = i + j;  
        }  
        env->SetIntArrayRegion(iarr, 0, size, tmp);  //爲iarr賦值
        env->SetObjectArrayElement(result, i, iarr);  //result的第i個元素賦值
        env->DeleteLocalRef(iarr);  
    }  
    return result;  
}  

上面代碼中的第三行,
jobjectArray result;
因爲要返回值,所以需要新建一個jobjectArray對象。

jclass intArrCls = env->FindClass("[I");
是創建一個jclass的引用,因爲result的元素是一維int數組的引用,所以intArrCls必須是一維int數組的引用,這一點是如何保證的呢?注意FindClass的參數"[I",JNI就是通過它來確定引用的類型的,I表示是int類型,[標識是數組。對於其他的類型,都有相應的表示方法,

Z boolean 
B byte 
C char 
S short 
I int 
J long 
F float 
D double

String是通過“Ljava/lang/String;”表示的,那相應的,String數組就應該是“[Ljava/lang/String;”。

"二維數組和String數組"這部分所用到的函數調用方式都是針對C++的,如果要在C中使用,所有的env->都要被替換成(*env)->,而且後面的函數中需要增加一個參數env


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章