NDK开发之访问域

Java有两类域,实例域和静态域。类的每个实例都有自己的实例域副本,而一个类的所有实例共享一个静态域(Java SE基础)。

JNI提供了相应的函数来访问这两类域,总体步骤是这样的:


1.通过对象引用获得类
2.通过类获得域ID
3.通过域ID获取域


下面我们按步骤一步一步来:
我们的Java类中有两个域,一个静态域,一个实例域:

    private static String staticFiled = "a static Filed465";
    private String instanceFiled = "a instance Filed123";

访问该域的三个步骤:

1通过对象引用获得类

jclass clazz;
    //定义域ID
    jfieldID instanceFieldId;
    jfieldID staticFieldId;
    //定义域
    jstring instanceFieldStr;
    jstring staticFieldStr;
    //通过对象引用获得类
    clazz = (*env)->GetObjectClass(env, thiz);

2通过类获得域ID

//通过类获得域ID
    instanceFieldId = (*env)->GetFieldID(env,clazz,"instanceFiled","Ljava/lang/String;");
    staticFieldId = (*env)->GetStaticFieldID(env,clazz,"staticFiled","Ljava/lang/String;");

这里两个函数的最后一个参数是Java中表示域类型的域描述符,"Ljava/lang/String;"表明域类型是String。
一般情况下,为了提高应用程序的性能,我们可以缓存域ID,一般总是缓存使用最频繁的域ID

3.通过域ID获取域

    //通过域ID获得域
    instanceFieldStr = (*env)->GetObjectField(env,thiz,instanceFieldId);
    staticFieldStr = (*env)->GetStaticObjectField(env,clazz,staticFieldId);

为了证明我们已经成功获得域,我们把jstring转为c字符串之后然后打印出来(打印日志请看NDK开发之日志打印):

    const jbyte* str1;
    const jbyte* str2;
    str1 = (*env)->GetStringUTFChars(env,instanceFieldStr,0);
    str2 = (*env)->GetStringUTFChars(env,staticFieldStr,0);
    LOGI("the string is :%s",str1);
    LOGI("the string is :%s",str2);

打印结果:

这里写图片描述


完整的程序是这样的:


void Java_com_example_jni_MainActivity_updateField(JNIEnv* env, jobject thiz) {
    jclass clazz;
    //定义域ID
    jfieldID instanceFieldId;
    jfieldID staticFieldId;
    //定义域
    jstring instanceFieldStr;
    jstring staticFieldStr;
    //通过对象引用获得类
    clazz = (*env)->GetObjectClass(env, thiz);
    //通过类获得域ID
    instanceFieldId = (*env)->GetFieldID(env,clazz,"instanceFiled","Ljava/lang/String;");
    staticFieldId = (*env)->GetStaticFieldID(env,clazz,"staticFiled","Ljava/lang/String;");
    //通过域ID获得域
    instanceFieldStr = (*env)->GetObjectField(env,thiz,instanceFieldId);
    staticFieldStr = (*env)->GetStaticObjectField(env,clazz,staticFieldId);
    //jstring转为C字符串然后打印出来
    const jbyte* str1;
    const jbyte* str2;
    str1 = (*env)->GetStringUTFChars(env,instanceFieldStr,0);
    str2 = (*env)->GetStringUTFChars(env,staticFieldStr,0);
    LOGI("the string is :%s",str1);
    LOGI("the string is :%s",str2);
}

总结

大家都看到了,获得单个域需要三个步骤,这真是太麻烦了,经常这样搞会影响程序的性能,因此建议如果在原生方法中需要 使用域,这些域最好作为参数传递给原生方法,而不要让原生代码回到Java中。


版权声明:本文为博主原创文章,未经博主允许不得转载。若有错误地方,还望批评指正,不胜感激。

posted @   江南一点雨  阅读(179)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示