JNI 操作 java 數(shù)組

在 jni 函數(shù)中對 java 數(shù)組的操作主要包含以下幾類:

  1. GetArrayLength(jarray array)

    用于返回 java 數(shù)組的數(shù)據(jù)長度

    jstring stringFromJNI(JNIEnv *env, jobject thiz, jintArray intArray){
        __android_log_print(ANDROID_LOG_INFO, "native", "stringFromJNI");
        
        jsize size = env->GetArrayLength(intArray);
        __android_log_print(ANDROID_LOG_INFO, "native", "data size %d", size);
    
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
  2. Get<Type>ArrayElements(<Type>Array arr , jboolean* isCopide) 與Release<Type>ArrayElements(<Type>Array arr , <Type>* array , jint mode)

    jboolean* GetBooleanArrayElements(jbooleanArray array, jboolean* isCopy)
    { return functions->GetBooleanArrayElements(this, array, isCopy); }
    jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy)
    { return functions->GetByteArrayElements(this, array, isCopy); }
    jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy)
    { return functions->GetCharArrayElements(this, array, isCopy); }
    jshort* GetShortArrayElements(jshortArray array, jboolean* isCopy)
    { return functions->GetShortArrayElements(this, array, isCopy); }
    jint* GetIntArrayElements(jintArray array, jboolean* isCopy)
    { return functions->GetIntArrayElements(this, array, isCopy); }
    jlong* GetLongArrayElements(jlongArray array, jboolean* isCopy)
    { return functions->GetLongArrayElements(this, array, isCopy); }
    jfloat* GetFloatArrayElements(jfloatArray array, jboolean* isCopy)
    { return functions->GetFloatArrayElements(this, array, isCopy); }
    jdouble* GetDoubleArrayElements(jdoubleArray array, jboolean* isCopy)
    { return functions->GetDoubleArrayElements(this, array, isCopy); }
    
    void ReleaseBooleanArrayElements(jbooleanArray array, jboolean* elems, jint mode)
    { functions->ReleaseBooleanArrayElements(this, array, elems, mode); }
    void ReleaseByteArrayElements(jbyteArray array, jbyte* elems, jint mode)
    { functions->ReleaseByteArrayElements(this, array, elems, mode); }
    void ReleaseCharArrayElements(jcharArray array, jchar* elems, jint mode)
    { functions->ReleaseCharArrayElements(this, array, elems, mode); }
    void ReleaseShortArrayElements(jshortArray array, jshort* elems, jint mode)
    { functions->ReleaseShortArrayElements(this, array, elems, mode); }
    void ReleaseIntArrayElements(jintArray array, jint* elems, jint mode)
    { functions->ReleaseIntArrayElements(this, array, elems, mode); }
    void ReleaseLongArrayElements(jlongArray array, jlong* elems, jint mode)
    { functions->ReleaseLongArrayElements(this, array, elems, mode); }
    void ReleaseFloatArrayElements(jfloatArray array, jfloat* elems, jint mode)
    { functions->ReleaseFloatArrayElements(this, array, elems, mode); }
    void ReleaseDoubleArrayElements(jdoubleArray array, jdouble* elems, jint mode)
    { functions->ReleaseDoubleArrayElements(this, array, elems, mode); }
    

    其中 Get<Type>ArrayElements 函數(shù)可以把Java基本類型的數(shù)組轉(zhuǎn)換到C/C++中的數(shù)組,有兩種處理方式,一種是拷貝一份傳回本地代碼,另一個是把指向Java數(shù)組的指針直接傳回到本地代碼中;該方法有兩個參數(shù),第一個參數(shù)指向了需要處理的數(shù)組,第二個參數(shù)用于表示把Java基本類型的數(shù)組轉(zhuǎn)換到C/C++中的數(shù)組具體使用的處理方式,也就是說是否發(fā)生了 數(shù)組copy;

    在完成數(shù)組數(shù)據(jù)處理后,調(diào)用 Release<Type>ArrayElements 方法,這個函數(shù)可以選擇將如何處理 Java 與 C++ 的數(shù)組,是提交,還是撤銷等,內(nèi)存釋放還是不釋放等;該方法有三個參數(shù),第一個參數(shù)指向了 java 數(shù)組,第二個參數(shù)指向調(diào)用 Get<Type>ArrayElements 函數(shù)返回的數(shù)組指針,第三個參數(shù)用于決定數(shù)組是提交,還是撤銷等,內(nèi)存釋放還是不釋放,其中包含三種模式:

    1. mode = 0
      • 原始數(shù)據(jù): 對象數(shù)組將不會被限制.
      • 拷貝數(shù)據(jù): 數(shù)據(jù)將會拷貝回原始數(shù)據(jù), 同時釋放拷貝數(shù)據(jù).
    2. mode = JNI_COMMIT (1)
      • 原始數(shù)據(jù): 什么都不作.
      • 拷貝數(shù)據(jù): 數(shù)據(jù)將會拷貝回原始數(shù)據(jù), 不釋放拷貝數(shù)據(jù).
    3. mode = JNI_ABORT (2)
      • 原始數(shù)據(jù): 對象數(shù)組將不會被限制, 之前的數(shù)據(jù)操作有效
      • 拷貝數(shù)據(jù): 釋放拷貝數(shù)據(jù), 之前的任何數(shù)據(jù)操作會丟棄.
    jstring stringFromJNI(JNIEnv *env, jobject thiz, jintArray intArray){
        __android_log_print(ANDROID_LOG_INFO, "native", "stringFromJNI");
        
        jboolean isCp = JNI_FALSE;
        jint* coldata = env->GetIntArrayElements(intArray, &isCp);
        __android_log_print(ANDROID_LOG_INFO, "native", "isCopy %d", isCp);
        jsize size = env->GetArrayLength(intArray);
        for (int j = 0; j < size; j++) {
            coldata[j] += 1;
        }
        env->ReleaseIntArrayElements(intArray, coldata, 0);
    
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    

    再具體使用過程中,先調(diào)用 GetIntArrayElements 獲取 java 數(shù)組的指針以及是否發(fā)生了拷貝;然后就可以對數(shù)組數(shù)據(jù)進行處理,在上訴代碼中只是做了 +1 操作,然后調(diào)用 ReleaseIntArrayElements 方法,其中 mode 為 0,也就是說將數(shù)據(jù)處理結(jié)構(gòu)同步到 java 數(shù)組,并釋放數(shù)組指針;

  3. GetPrimitiveArrayCritical(jarray arr , jboolean* isCopied) 與 ReleasePrimitiveArrayCritical(jarray arr , void* array , jint mode)

    這兩個方法與上面的 Get<Type>ArrayElements 與Release<Type>ArrayElements 方法非常像,但是有一點很重要的不同:GetPrimitiveArrayCritical 更傾向于也更容易獲取 java 中數(shù)組的指針而不進行拷貝,這也導(dǎo)致在調(diào)用 GetPrimitiveArrayCritical 與 ReleasePrimitiveArrayCritical 不能執(zhí)行耗時很長的操作或者需要阻塞并等待的操作,而且在這之間 JVM 很可能會暫時禁用GC;

    jstring stringFromJNI(JNIEnv *env, jobject thiz, jintArray intArray){
    
        __android_log_print(ANDROID_LOG_INFO, "native", "stringFromJNI");
        jboolean isCp = JNI_FALSE;
        jint* coldata = static_cast<jint *>(env->GetPrimitiveArrayCritical(intArray, &isCp));
        __android_log_print(ANDROID_LOG_INFO, "native", "isCopy %d", isCp);
        jsize size = env->GetArrayLength(intArray);
        for (int j = 0; j < size; j++) {
            coldata[j] += 1;
        }
        env->ReleasePrimitiveArrayCritical(intArray, coldata, 0);
    
     std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
  4. Get<Type>ArrayRegion(<Type>Array arr , jsize start , jsize len , <Type>* buffer)

    void GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf)
    { functions->GetBooleanArrayRegion(this, array, start, len, buf); }
    void GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf)
    { functions->GetByteArrayRegion(this, array, start, len, buf); }
    void GetCharArrayRegion(jcharArray array, jsize start, jsize len,jchar* buf)
    { functions->GetCharArrayRegion(this, array, start, len, buf); }
    void GetShortArrayRegion(jshortArray array, jsize start, jsize len,jshort* buf)
    { functions->GetShortArrayRegion(this, array, start, len, buf); }
    void GetIntArrayRegion(jintArray array, jsize start, jsize len,jint* buf)
    { functions->GetIntArrayRegion(this, array, start, len, buf); }
    void GetLongArrayRegion(jlongArray array, jsize start, jsize len,jlong* buf)
    { functions->GetLongArrayRegion(this, array, start, len, buf); }
    void GetFloatArrayRegion(jfloatArray array, jsize start, jsize len,jfloat* buf)
    { functions->GetFloatArrayRegion(this, array, start, len, buf); }
    void GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,jdouble* buf)
    { functions->GetDoubleArrayRegion(this, array, start, len, buf); }
    

    在 jni 預(yù)先開辟一段內(nèi)存,然后把 Java 數(shù)組拷貝到這段內(nèi)存中; 該方法有四個參數(shù),第一個指向的是 java 數(shù)組,第二個參數(shù)表示開始位置,第三個參數(shù)表示拷貝的長度,第四個指向目標(biāo)緩沖區(qū);

    jstring stringFromJNI(JNIEnv *env, jobject thiz, jintArray intArray){
        __android_log_print(ANDROID_LOG_INFO, "native", "stringFromJNI");
        
        jsize size = env->GetArrayLength(intArray);
        jint* data = new jint[size];
        env->GetIntArrayRegion(intArray, 0, size, data);
        for (int j = 0; j < size; j++) {
            __android_log_print(ANDROID_LOG_INFO, "native", "data %d", data[j]);
        }
        
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
  5. Set<Type>ArrayRegion(<Type>Array arr , jsize start , jsize len , const <Type>* buffer)

    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len,const jboolean* buf)
    { functions->SetBooleanArrayRegion(this, array, start, len, buf); }
    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,const jbyte* buf)
    { functions->SetByteArrayRegion(this, array, start, len, buf); }
    void SetCharArrayRegion(jcharArray array, jsize start, jsize len,const jchar* buf)
    { functions->SetCharArrayRegion(this, array, start, len, buf); }
    void SetShortArrayRegion(jshortArray array, jsize start, jsize len,const jshort* buf)
    { functions->SetShortArrayRegion(this, array, start, len, buf); }
    void SetIntArrayRegion(jintArray array, jsize start, jsize len,const jint* buf)
    { functions->SetIntArrayRegion(this, array, start, len, buf); }
    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,const jlong* buf)
    { functions->SetLongArrayRegion(this, array, start, len, buf); }
    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len,const jfloat* buf)
    { functions->SetFloatArrayRegion(this, array, start, len, buf); }
    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,const jdouble* buf)
    { functions->SetDoubleArrayRegion(this, array, start, len, buf); }
    

    把 Java 數(shù)組中的指定范圍的元素用 jni 數(shù)組中的元素來賦值,該方法有四個參數(shù),第一個指向的是目標(biāo) java 數(shù)組,第二個參數(shù)表示開始位置,第三個參數(shù)表示拷貝的長度,第四個指向 jni 數(shù)組;

    jstring stringFromJNI(JNIEnv *env, jobject thiz, jintArray intArray){
        __android_log_print(ANDROID_LOG_INFO, "native", "stringFromJNI");
        
        jsize size = env->GetArrayLength(intArray);
        jint* data = new jint[size];
        for (int j = 0; j < size; j++) {
            data[j] = j;
        }
        env->SetIntArrayRegion(intArray, 0, size, data);
    
        std::string hello = "Hello from C++";
        return env->NewStringUTF(hello.c_str());
    }
    
  6. <Type>Array New<Type>Array(jsize sz)

    jbooleanArray NewBooleanArray(jsize length)
    { return functions->NewBooleanArray(this, length); }
    jbyteArray NewByteArray(jsize length)
    { return functions->NewByteArray(this, length); }
    jcharArray NewCharArray(jsize length)
    { return functions->NewCharArray(this, length); }
    jshortArray NewShortArray(jsize length)
    { return functions->NewShortArray(this, length); }
    jintArray NewIntArray(jsize length)
    { return functions->NewIntArray(this, length); }
    jlongArray NewLongArray(jsize length)
    { return functions->NewLongArray(this, length); }
    jfloatArray NewFloatArray(jsize length)
    { return functions->NewFloatArray(this, length); }
    jdoubleArray NewDoubleArray(jsize length)
    { return functions->NewDoubleArray(this, length); }
    

    使用 NewBooleanArray(jsize length) 可以返回一個指定長度的 java 數(shù)組;

  7. jobject GetObjectArrayElement(jobjectArray array, jsize index) 與 void SetObjectArrayElement(jobjectArray array, jsize index, jobject value)

    上面所述的對于數(shù)組的操作除了 GetArrayLength 方法是對于基本類型數(shù)組與對象數(shù)組通用的,其它均是用于操作基本類型數(shù)組;GetObjectArrayElement 與 SetObjectArrayElement 提供了對于對象數(shù)組的操作 GetObjectArrayElement 方法用于返回對象數(shù)組中指定位置的對象;SetObjectArrayElement 用于更新對象數(shù)組中指定位置的對象;

  8. jobjectArray NewObjectArray(jsize length, jclass elementClass, jobject initialElement)

    之前提到 New<Type>Array 方法用于創(chuàng)建 java 基本類型數(shù)組,對應(yīng)的 NewObjectArray 用于創(chuàng)建 java 對象數(shù)組,該方法包含三個參數(shù),第一個參數(shù)表示數(shù)組長度,第二個參數(shù)表示類,第三個參數(shù)表示元素初始值;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容