JNI&NDK開發最佳實踐(七):JNI之本地方法與java互調

java調用本地方法

java調用本地方法主要有如下兩個場景:

本地方法調用java

C/C++訪問Java實例方法和靜態方法

// AccessMethod.c
 
#include "com_study_jnilearn_AccessMethod.h"
 
/*
 * Class:     com_study_jnilearn_AccessMethod
 * Method:    callJavaStaticMethod
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaStaticMethod
(JNIEnv *env, jclass cls)
{
    jclass clazz = NULL;
    jstring str_arg = NULL;
    jmethodID mid_static_method;
    // 1、從classpath路徑下搜索ClassMethod這個類,并返回該類的Class對象
    clazz =(*env)->FindClass(env,"com/study/jnilearn/ClassMethod");
    if (clazz == NULL) {
        return;
    }
    
    // 2、從clazz類中查找callStaticMethod方法
    mid_static_method = (*env)->GetStaticMethodID(env,clazz,"callStaticMethod","(Ljava/lang/String;I)V");
    if (mid_static_method == NULL) {
        printf("找不到callStaticMethod這個靜態方法。");
        return;
    }
    
    // 3、調用clazz類的callStaticMethod靜態方法
    str_arg = (*env)->NewStringUTF(env,"我是靜態方法");
    (*env)->CallStaticVoidMethod(env,clazz,mid_static_method, str_arg, 100);
    
    // 刪除局部引用
    (*env)->DeleteLocalRef(env,clazz);
    (*env)->DeleteLocalRef(env,str_arg);
}
 
/*
 * Class:     com_study_jnilearn_AccessMethod
 * Method:    callJavaInstaceMethod
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessMethod_callJavaInstaceMethod
(JNIEnv *env, jclass cls)
{
    jclass clazz = NULL;
    jobject jobj = NULL;
    jmethodID mid_construct = NULL;
    jmethodID mid_instance = NULL;
    jstring str_arg = NULL;
    // 1、從classpath路徑下搜索ClassMethod這個類,并返回該類的Class對象
    clazz = (*env)->FindClass(env, "com/study/jnilearn/ClassMethod");
    if (clazz == NULL) {
        printf("找不到'com.study.jnilearn.ClassMethod'這個類");
        return;
    }
    
    // 2、獲取類的默認構造方法ID
    mid_construct = (*env)->GetMethodID(env,clazz, "<init>","()V");
    if (mid_construct == NULL) {
        printf("找不到默認的構造方法");
        return;
    }
    
    // 3、查找實例方法的ID
    mid_instance = (*env)->GetMethodID(env, clazz, "callInstanceMethod", "(Ljava/lang/String;I)V");
    if (mid_instance == NULL) {
        
        return;
    }
    
    // 4、創建該類的實例
    jobj = (*env)->NewObject(env,clazz,mid_construct);
    if (jobj == NULL) {
        printf("在com.study.jnilearn.ClassMethod類中找不到callInstanceMethod方法");
        return;
    }
    
    // 5、調用對象的實例方法
    str_arg = (*env)->NewStringUTF(env,"我是實例方法");
    (*env)->CallVoidMethod(env,jobj,mid_instance,str_arg,200);
    
    // 刪除局部引用
    (*env)->DeleteLocalRef(env,clazz);
    (*env)->DeleteLocalRef(env,jobj);
    (*env)->DeleteLocalRef(env,str_arg);
}

C/C++訪問Java實例變量和靜態變量

// AccessField.c
 
#include "com_study_jnilearn_AccessField.h"
 
/*
 * Class:     com_study_jnilearn_AccessField
 * Method:    accessInstanceField
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField
(JNIEnv *env, jclass cls, jobject obj)
{
    jclass clazz;
    jfieldID fid;
    jstring j_str;
    jstring j_newStr;
    const char *c_str = NULL;
    
    // 1.獲取AccessField類的Class引用
    clazz = (*env)->GetObjectClass(env,obj);
    if (clazz == NULL) {
        return;
    }
    
    // 2. 獲取AccessField類實例變量str的屬性ID
    fid = (*env)->GetFieldID(env,clazz,"str", "Ljava/lang/String;");
    if (clazz == NULL) {
        return;
    }
    
    // 3. 獲取實例變量str的值
    j_str = (jstring)(*env)->GetObjectField(env,obj,fid);
    
    // 4. 將unicode編碼的java字符串轉換成C風格字符串
    c_str = (*env)->GetStringUTFChars(env,j_str,NULL);
    if (c_str == NULL) {
        return;
    }
    printf("In C--->ClassField.str = %s\n", c_str);
    (*env)->ReleaseStringUTFChars(env, j_str, c_str);
    
    // 5. 修改實例變量str的值
    j_newStr = (*env)->NewStringUTF(env, "This is C String");
    if (j_newStr == NULL) {
        return;
    }
    
    (*env)->SetObjectField(env, obj, fid, j_newStr);
    
    // 6.刪除局部引用
    (*env)->DeleteLocalRef(env, clazz);
    (*env)->DeleteLocalRef(env, j_str);
    (*env)->DeleteLocalRef(env, j_newStr);
}
 
/*
 * Class:     com_study_jnilearn_AccessField
 * Method:    accessStaticField
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessStaticField
(JNIEnv *env, jclass cls)
{
    jclass clazz;
    jfieldID fid;
    jint num;
    
    //1.獲取ClassField類的Class引用
    clazz = (*env)->FindClass(env,"com/study/jnilearn/ClassField");
    if (clazz == NULL) {    // 錯誤處理
        return;
    }
    
    //2.獲取ClassField類靜態變量num的屬性ID
    fid = (*env)->GetStaticFieldID(env, clazz, "num", "I");
    if (fid == NULL) {
        return;
    }
    
    // 3.獲取靜態變量num的值
    num = (*env)->GetStaticIntField(env,clazz,fid);
    printf("In C--->ClassField.num = %d\n", num);
    
    // 4.修改靜態變量num的值
    (*env)->SetStaticIntField(env, clazz, fid, 80);
    
    // 刪除屬部引用
    (*env)->DeleteLocalRef(env,clazz);
}

更多JNI&NDK系列文章,參見:
JNI&NDK開發最佳實踐(一):開篇
JNI&NDK開發最佳實踐(二):CMake實現調用已有C/C++文件中的本地方法
JNI&NDK開發最佳實踐(三):CMake實現調用已有so庫中的本地方法
JNI&NDK開發最佳實踐(四):JNI數據類型及與Java數據類型的映射關系
JNI&NDK開發最佳實踐(五):本地方法的靜態注冊與動態注冊
JNI&NDK開發最佳實踐(六):JNI實現本地方法時的數據類型轉換
JNI&NDK開發最佳實踐(七):JNI之本地方法與java互調
JNI&NDK開發最佳實踐(八):JNI局部引用、全局引用和弱全局引用
JNI&NDK開發最佳實踐(九):調試篇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。