JNI訪問Java類的靜態成員

上篇文章JNI訪問Java對象的成員介紹瞭如何在JNI層回調Java對象的成員(變量和方法),這篇文章是上篇文章 的姊妹篇,介紹在JNI層如何回調Java類的靜態成員(變量和方法)。java

例子

首先呢,仍是須要作一些準備工做,先完成動態註冊的代碼。android

若是你對動態註冊的代碼還不熟悉,能夠經過JNI函數動態註冊JNI函數動態註冊進階學習。c++

首先在Java類中加載動態庫,而後調用native方法,代碼以下數組

package com.umx.ndkdemo;

public class Person {
    private static String mName = "Nobody";

    static {
        System.loadLibrary("person_jni");
    }

    public native void native_hello();

    public static void sayHello() {
        System.out.println(mName + ": Hello World!");
    }
    
    public static void main(String[] args) {
        new Person().native_hello();
    }
}


複製代碼

而後在JNI層進行動態註冊函數

#include "jni.h"

static void com_umx_ndkdemo_Person_native_hello(JNIEnv *env, jobject thiz) {

}

static const JNINativeMethod nativeMethods[] = {
        {"native_hello", "()V", (void *) com_umx_ndkdemo_Person_native_hello}
};

jint JNI_OnLoad(JavaVM * vm, void * reserved) {
    jint jni_version = -1;
    JNIEnv* env = NULL;

    if (vm->GetEnv((void **)&env, JNI_VERSION_1_1) == JNI_OK) {
        jclass clazz_Person = env->FindClass("com/umx/ndkdemo/Person");
        if (env->RegisterNatives(clazz_Person, nativeMethods,
                                 sizeof(nativeMethods) / sizeof(nativeMethods[0])) == JNI_OK) {
            jni_version = JNI_VERSION_1_6;
        }
    }
    return jni_version;
}
複製代碼

com_umx_ndkdemo_Person_native_hello就是要實現的方法,在這個方法中將會作三件事情post

  • 獲取Hello.java類的靜態變量mName的值。
  • 從新設置Hello.java類的靜態變量mName的值。
  • 調用Hello.java的靜態方法sayHello

訪問Java類的靜態變量

獲取靜態變量的值

首先實現獲取Hello.java靜態變量mName的值學習

#include <android/log.h>
static void com_umx_ndkdemo_Person_native_hello(JNIEnv *env, jobject thiz) {
    // 獲取Class對象
    jclass clazz_Person = env->FindClass("com/umx/ndkdemo/Person");
    // 從Class對象中獲取mName字段
    jfieldID fieldID_mName = env->GetStaticFieldID(clazz_Person, "mName", "Ljava/lang/String;");
    // 獲取靜態變量的值
    jstring mName = (jstring) env->GetStaticObjectField(clazz_Person, fieldID_mName);
    // 打印輸出
    __android_log_print(ANDROID_LOG_INFO, "bxll", "name = %\n", mName);
}
複製代碼

和Java反射相似,使用JNI獲取Java類的靜態變量的步驟以下spa

  • 獲取Class對象
  • 獲取Class對象的字段名,也就是靜態變量名
  • 經過Class對象和字段名,獲取靜態變量的值

FindClass

在例子中是經過FindClass函數來獲取Class對象的,函數原型以下code

jclass FindClass(JNIEnv *env, const char *name);
複製代碼

參數const char * name能夠是全限定的Class名,或者是一個數組類型的簽名。對象

  • 對於Java的String類,全限定Class名爲java.lang.String,可是因爲點號在JNI中有特殊意義,所以使用斜線來代替點號,全限定Class名爲java/lang/String
  • 對於Java的數組類,例如String[],那麼參數就要爲數組的類型簽名[Ljava/lang/String;

若是還不瞭解數組的類型的簽名是什麼,可能參數JNI函數動態註冊進階

GetStaticFieldID

在例子中,是經過GetStaticFieldID函數來獲取Class對象的靜態字段,函數原型以下

jfieldID GetStaticFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig);
複製代碼

參數

  • jclass clazz: Class對象,經過FindClass函數獲取。
  • const char *name: Class對象的字段名,也就是Java類的靜態變量名。
  • const char *sig: 靜態變量的類型簽名。

若是還不瞭解數組的類型的簽名是什麼,可能參數JNI函數動態註冊進階

GetStatic<type>Field

根據Java類的靜態變量的類型的不一樣,在JNI中有不一樣的方法來獲取靜態變量的值,可是基本形式以下

NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz, jfieldID fieldID);
複製代碼

這類函數能夠是爲兩類,一類是處理Java的8種基本類型,一類是處理全部的Java引用類型,以下表

方法名 返回值
GetStaticBooleanField jboolean
GetStaticByteField jbyte
GetStaticCharField jchar
GetStaticShortField jshort
GetStaticIntField jint
GetStaticLongField jlong
GetStaticFloatField jfloat
GetStaticDoubleField jdouble
GetStaticObjectField jobject

前8項是處理Java對應的8種基本類型,最後一項是處理其它全部的Java類型。

例如,對於Java類的int類型的靜態變量,是用以下函數獲取

jint GetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID);
複製代碼

而對於Java的String類型的靜態變量,是用以下函數獲取的

jstring GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID);
複製代碼

設置靜態變量的值

如今來實現設置靜態變量的值

static void com_umx_ndkdemo_Person_native_hello(JNIEnv *env, jobject thiz) {
    // 獲取Class對象
    jclass clazz_Person = env->FindClass("com/umx/ndkdemo/Person");
    // 獲取字段
    jfieldID fieldID_mName = env->GetStaticFieldID(clazz_Person, "mName", "Ljava/lang/String;");
    // 設置字段的值
    jstring name = env->NewStringUTF("David");
    env->SetStaticObjectField(clazz_Person, fieldID_mName, name);

}
複製代碼

設置Java類靜態變量的值有如下幾步

  • 獲取Java類的Class對象
  • 獲取靜態變量的字段
  • 經過Class對象和字符,設置靜態變量的值

前兩步與已經介紹過,直接說明第三步是如何使用的

SetStatic<type>Field

根據Java類的靜態變量的類型的不一樣,在JNI中有不一樣的方法來獲設置態變量的值,可是基本形式以下

void SetStatic<type>Field(JNIEnv *env, 
                        jclass clazz,
                        jfieldID fieldID, 
                        NativeType value);
複製代碼

其中最後一個參數指的是要給Java類的靜態變量設置的值,它的類型會根據要設置的靜態變量的類型的不一樣而不一樣,例如,要給int類型的靜態變量設置值,那麼這裏的NativeType就對應jint

JNI處理Java類型的方式分爲基本類型(8種)的引用類型,所以這裏對應的JNI方法就有9種

方法名 NativeType
SetStaticBooleanField jboolean
SetStaticByteField jbyte
SetStaticCharField jchar
SetStaticShortField jshort
SetStaticIntField jint
SetStaticLongField jlong
SetStaticFloatField jfloat
SetStaticDoubleField jdouble
SetStaticObjectField jobject

前8項就是用來設置Java的基本類型的,最後一項就是用來處理Java引用類型的。

例如,若是要給Java類的int類型的靜態變量設置值,那麼就要調用以下函數

void SetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
複製代碼

例如,若是要給Java類的String類型的變量設置值,那麼就要調用以下的函數

void SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value) 複製代碼

完整實現

static void com_umx_ndkdemo_Person_native_hello(JNIEnv *env, jobject thiz) {
    jclass clazz_Person = env->FindClass("com/umx/ndkdemo/Person");
    if (clazz_Person == NULL)
    {
        return;
    }

    jfieldID fieldID_mName = env->GetStaticFieldID(clazz_Person, "mName", "Ljava/lang/String;");
    if (fieldID_mName == NULL)
    {
        return;
    }

    jstring mName = (jstring) env->GetStaticObjectField(clazz_Person, fieldID_mName);
    __android_log_print(ANDROID_LOG_INFO, "david", "name = %\n", mName);

    jstring name = env->NewStringUTF("David");
    env->SetStaticObjectField(clazz_Person, fieldID_mName, name);
    
    jmethodID methodID_sayHello = env->GetStaticMethodID(clazz_Person, "sayHello", "()V");
    env->CallStaticVoidMethod(clazz_Person, methodID_sayHello);

    // 刪除局部引用(可選)
    env->DeleteLocalRef(name);
    env->DeleteLocalRef(mName);
    env->DeleteLocalRef(clazz_Person);
}
複製代碼

在這個完整實現中,加入了對jclassjmethodID的判空,以及手動刪除局部引用的操做。

總結

這篇文章其實和上篇文章很是相似,也很是好理解,只要搞清楚了流程,就能夠很是熟練的使用了。

其實還有一個很是有意思的事情,如何訪問(獲取/設置)Java的數組類型的靜態變量?恩,這個問題留到下一篇文章來分析。

相關文章
相關標籤/搜索