六、(2)缓存jfieldID、jmethodID

缓存jfieldID/jmethodID

取得jfieldID和jmethodID的时候通过该属性/方法名称加上签名来查询相应的ID,这种查询相对来说开销较大.我们可以将这些ID缓存起来,这样只需要查询一次,以后使用已经缓存的ID

两种缓存方式

1、在第一次使用的时候缓存 (Caching at the Point of Use)

在native code 中使用static局部变量来保存已经查询过得id.这样就不会在每次的函数调用时查询,只要在查询成功后就保存起来了,在这种情况下就不得不考虑多线程同时调用此函数时可能会招致同时查询的危机,不过这种方式是无害的,因为查询同一个属性/方法的ID通常返回的是一样的值,下面是一个简单的代码:

//对 com_fomagic_TestNative.h 中声明的方法定义
JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *env, jobject obj)
{
    static jfieldID fieldID_string=NULL;
    jclass clazz=env->GetObjectClass(obj);
 
    if (fieldID_string==NULL)
    {
        fieldID_string=env->GetFieldID(clazz,"string","Ljava/lang/String;");
    }
}

 

2、在Java类初始化时缓存 (Caching at the Defining Class’s Initializer)

更好的一个方式就是在任何native函数调用前把id全部存起来我们可以让Java在第一次加载这个类的时候首先调用本地代码初始化所有的jfieldID/jmethodID,这样的话就可以省去多次的确定ID是否存在的语句,当然这些jfieldID/jmethodID是定义在C/C++的全局。使用这种方式的好处,当Java类卸载或是重新加载的时候也会重新调用本地代码来重新计算IDs

Java不完整代码:

package com.fomagic;
public class TestNative {
 
    static{
        sayHello();
    }
    static native void sayHello(); // C++本地代码实现
    
    int propInt=0;
    String propStr="";
    public native void otherNative();
    
    //other code...
}


C++不完整代码:

jfieldID g_propInt_id=0;
jfieldID g_propStr_id=0;
 
//对 com_fomagic_TestNative.h 中声明的方法定义
JNIEXPORT void JNICALL Java_com_fomagic_TestNative_sayHello (JNIEnv *env, jobject obj)
{
    jclass clazz=env->GetObjectClass(obj);
    g_propInt_id=env->GetFieldID(clazz,"propInt","I");
    g_propStr_id=env->GetFieldID(clazz,"propStr","Ljava/lang/String;");
 
}
 
JNIEXPORT void JNICALL Java_com_fomagic_TestNative_otherNative (JNIEnv *env, jobject obj)
{
    //get field with g_propInt_id/g_propStr_id....
}
 

 最后

还需要学习的知识:

  • 异常处理
  • C/C++如何启动JVM
  • JNI跟多线程

推荐的书籍读物:

  • The Java Native Interface Programmer’s Guide and Specification
  • JNI++ User Guide

你可能感兴趣的:(JNI笔记)