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的数组类型的静态变量?恩,这个问题留到下一篇文章来分析。

相关文章
相关标签/搜索