04 jni调用java方法

    xiaoxiao2024-11-23  64

    JNI本地方法访问Java属性和方法

    在JNI调用中,不仅仅Java可以调用本地方法,本地代码也可以调用Java中的方法和成员变量。在Java1.0中“原始的”Java到C的绑定中,程序员可以直接访问对象数据域。然而,直接方法要求虚拟机暴露他们的内部数据布局,基于这个原因,JNI要求程序员通过特殊的JNI函数来获取和设置数据以及调用java方法。

     

     

    取得代表属性和方法的jfieldID和jmethodID

     

    为了在C/C++中表示属性和方法,JNI在jni.h头文件中定义了jfieldID和jmethodID类型来分别代表Java对象的属性和方法。我们在访问或是设置Java属性的时候,首先就要先在本地代码取得代表该Java属性的jfieldID,然后才能在本地代码进行Java属性操作。同样的,我们需要调用Java对象方法时,也是需要取得代表该方法的jmethodID才能进行Java方法调用。

     

    使用JNIEnv提供的JNI方法,我们就可以获得属性和方法相对应的jfieldID和jmethodID:

     

    l GetFieldID :取得成员变量的id

    l GetStaticFieldID :取得静态成员变量的id

    l GetMethodID :取得方法的id

    l GetStaticMethodID :取得静态方法的id

     

    jfieldID GetFieldID(jclass clazz, const char *name,const char *sig)

    jfieldID GetStaticFieldID(jclass clazz, const char*name, const char *sig)

    jmethodID GetStaticMethodID(jclass clazz, const char*name, const char *sig)

    jmethodID GetMethodID(jclass clazz, const char *name,constchar *sig)

     

    第一个参数jclassclazz :

    上一节讲到的jclass类型,相当于Java中的Class类,代表一个Java类,而这里面的代表的就是我们操作的Class类,我们要从这个类里面取的属性和方法的ID。

     

    第二个参数constchar *name:

    这是一个常量字符数组,代表我们要取得的方法名或者变量名。

     

    第三个参数constchar *sig:

    这也是一个常量字符数组,代表我们要取得的方法或变量的签名。(变量类型)

     

    类型签名Java 类型类型签名Java 类型ZbooleanVvoidBbyteLjava/lang/StringStringCcharLjava/lang/ObjectObjectSshortFfloatIintDdoubleJlongLJava对象以L开头,然后以“/”分隔包的完整类型,

     

    示例:String substr(String str, int idx, int count);

    对应的类型签名(Ljava/lang/String;II)Ljava/lang/String

     

    获取/设置 属性/静态属性

    获取属性/静态属性的形式:

    Get<Type>Field GetStatic<Type>Field。

    设置属性/静态属性的形式:

    Set<Type>Field SetStatic<Type>Field。

     

    取得成员属性:

    jobject GetObjectField(jobjectobj, jfieldID fieldID);

    jboolean GetBooleanField(jobjectobj, jfieldID fieldID);

    jbyte GetByteField(jobjectobj, jfieldID fieldID);

     

    取得静态属性:

    jobject GetStaticObjectField(jclassclazz, jfieldID fieldID);

    jboolean GetStaticBooleanField(jclassclazz, jfieldID fieldID);

    jbyte GetStaticByteField(jclassclazz, jfieldID fieldID);

    Get方法的第一个参数代表要获取的属性所属对象或jclass对象,第二个参数即属性ID。

     

    设置成员属性:

    void SetObjectField(jobjectobj, jfieldID fieldID, jobject val);

    void SetBooleanField(jobjectobj, jfieldID fieldID,jboolean val);

    void SetByteField(jobjectobj, jfieldID fieldID, jbyte val);

     

    设置静态属性:

    void SetStaticObjectField(jobjectobj, jfieldID fieldID, jobject val);

    void SetStaticBooleanField(jobjectobj, jfieldID fieldID,jboolean val);

    void SetStaticByteField(jobjectobj, jfieldID fieldID, jbyte val);

    Set方法的第一个参数代表要设置的属性所属的对象或jclass对象,第二个参数即属性ID,第三个参数代表要设置的值。

     

     

    调用方法

     

    取得了代表方法和静态方法的jmethodID,就可以用在JNIEnv中提供的方法来调用方法和静态方法。

     

    调用普通方法:

    Call<Type>Method(jobject obj, jmethodID methodID,...);

    Call<Type>MethodV(jobject obj, jmethodID methodID,va_listargs);

    Call<Type>tMethodA(jobject obj, jmethodID methodID,constjvalue *args);

     

    调用静态方法:

    CallStatic<Type>Method(jclass clazz, jmethodID methodID,...);

    CallStatic<Type>MethodV(jclass clazz, jmethodID methodID,va_listargs);

    CallStatic<Type>tMethodA(jclass clazz, jmethodID methodID,constjvalue *args);

     

    上面的Type这个方法的返回值类型,如Int,Char,Byte等等。

    第一个参数代表调用的这个方法所属于的对象,或者这个静态方法所属的类。

    第二个参数代表jmethodID。

    后面的参数,就代表这个方法的参数列表了。

     

     

    本地代码部分:

    //首先取得要调用的方法所在的类的Class对象,在C/C++中即jclass对象

    jclass clazz_NativeTest=env->FindClass("cn/itcast/NativeTest");

    //取得jmethodID

    jmethodID id_show=env->GetMethodID(clazz_NativeTest,“show”,"(I)V");

    //调用java函数

    env->CallIntMethod(obj, id_show, i); //i类型为 jint

    最新回复(0)