美文网首页
四、JNI-成员和方法

四、JNI-成员和方法

作者: MrDecoder | 来源:发表于2021-03-23 19:30 被阅读0次
  • 成员
  • 方法

#1. 成员

Java中成员变量分为普通成员变量和静态成员变量。普通成员变量也称为类实例成员变量,所有类的实例都有自己的成员变量副本;静态成员变量也称为类成员变量,所有类的实例共享类的静态成员变量。

JNI层也据此提供了两类访问成员变量的方式:一类是访问类实例的成员变量,另一类是访问类的成员变量。

1.1 访问实例成员

访问类实例成员分为两个步骤:

  1. 调用GetFiledID去获取类的field ID
jfieldID fId = env->GetFieldID(objClazz, "s", "Ljava/lang/String;");
  1. 调用Get<type>Field获取实例成员,Get<type>Field接受field ID作为参数。
jstring jstr = (jstring) env->GetObjectField(obj, fId);
1.1.1 GetObjectClass

获取实例所属的类。

jclass GetObjectClass(JNIEnv *env, jobject obj);
1.1.2 GetFieldID

通过指定成员变量的名字和签名,获取类实例的成员ID。获取的ID通过Get<type>Field和Set<type>Field函数集可以对类实例成员进行读写。

jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
1.1.3 Get<type>Field Routines

Get系列函数用来获取类实例成员变量的值。参数fieldID即是通过调用GetFieldID获得。

NativeType Get<type>Field(JNIEnv *env, jobject obj,jfieldID fieldID);
Get<type>Field Routine Name Native Type
GetObjectField() jobject
GetBooleanField() jboolean
GetByteField() jbyte
GetCharField() jchar
GetShortField() jshort
GetIntField() jint
GetLongField() jlong
GetFloatField() jfloat
GetDoubleField() jdouble
1.1.4 Set<type>Field Routines

Set系列函数集用来给类实例成员变量设置值。参数fieldID即是通过调用GetFieldID获得。

void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
Set<type>Field Routine Native Type
SetObjectField() jobject
SetBooleanField() jboolean
SetByteField() jbyte
SetCharField() jchar
SetShortField() jshort
SetIntField() jint
SetLongField() jlong
SetFloatField() jfloat
SetDoubleField() jdouble
1.1.5 示例
public class InstanceFieldAccess {
    static {
        System.loadLibrary("jnitest");
    }

    public String s;

    public native void accessField();
}

JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_InstanceFieldAccess_accessField
        (JNIEnv *env, jobject obj) {
    jfieldID fId;
    jstring jstr;
    //Get a reference to obj's class.
    jclass objClazz = env->GetObjectClass(obj);
    if (objClazz == nullptr) {
        return;
    }
    //Get field s of instance obj.
    fId = env->GetFieldID(objClazz, "s", "Ljava/lang/String;");
    if (fId == nullptr) {
        return;
    }
    //Read the instance field s.
    jstr = (jstring) env->GetObjectField(obj, fId);
    if (jstr == nullptr) {
        return;
    }
    const char *str = env->GetStringUTFChars(jstr, nullptr);
    printf(" c.s = \"%s\"\n", str);
    env->ReleaseStringUTFChars(jstr, str);

    jstr = env->NewStringUTF("123");
    if (jstr == nullptr) {
        return;
    }
    //Overwrite the instance field.
    env->SetObjectField(obj, fId, jstr);
}
1.2 访问类成员
1.2.1 GetStaticFieldID

通过指定类成员的名字和签名,获取类的成员ID。获取的ID通过GetStatic<type>Field和SetStatic<type>Field函数集可以对类成员进行读写。

jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
1.2.2 GetStatic<type>Field Routines

Get系列函数集用来获取类成员变量的值。参数fieldID即是通过调用GetStaticFieldID获得。

NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID);
GetStatic<type>Field Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble
1.2.3 SetStatic<type>Field Routines

Set系列函数集用来设置类成员变量的值。参数fieldID即是通过调用GetStaticFieldID获得。

void SetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
SetStatic<type>Field Routine Native Type
SetStaticObjectField() jobject
SetStaticBooleanField() jboolean
SetStaticByteField() jbyte
SetStaticCharField() jchar
SetStaticShortField() jshort
SetStaticIntField() jint
SetStaticLongField() jlong
SetStaticFloatField() jfloat
SetStaticDoubleField() jdouble
1.2.4 示例
public class InstanceFieldAccess {
    static {
        System.loadLibrary("jnitest");
    }

    public static int num;

    public native void accessStaticField();
}

JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_InstanceFieldAccess_accessStaticField
        (JNIEnv *env, jobject obj) {
    jclass clazz;
    jfieldID fid;

    clazz = env->GetObjectClass(obj);
    if (clazz == nullptr) {
        return;
    }
    fid = env->GetStaticFieldID(clazz, "num", "I");
    if (fid == nullptr) {
        return;
    }
    jint num = env->GetStaticIntField(clazz, fid);
    printf(" StaticFieldAccess.num = %d\n", num);

    env->SetStaticIntField(clazz, fid, 300);
}

#2. 方法

Java中方法分为实例方法和类方法两种。JNI层提供了对应函数集来进行相应的函数调用。

2.1 访问实例方法

JNI层访问实例方法分为两个步骤:

  1. 通过GetMethodID查找实例方法,获取对应jmethodID。查找的是基于函数名字和函数签名。
  2. 调用Call<type>Method调用实例方法,Call<type>Method接受jmethodID作为参数。
2.1.1 GetMethodID

通过指定实例方法的名字和签名来获取类实例的方法ID。函数签名是以函数参数类型和返回值类型作为描述符。

jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);

签名示例:

private native String getLine(String);
//Signature
"(Ljava/lang/String;)Ljava/lang/String;"
2.1.2 Call<type>Method Routines

Call<type>Method,Call<type>MethodA和Call<type>MethodV函数系列用来调用实例方法。他们的区别在于传递函数所需参数的方式不同。

  • Call<type>Method Routines通过可变参数列表传递函数参数。
  • Call<type>MethodA Routines通过jvalues数组传递函数参数。
  • Call<type>MethodV Routines通过va_list传递函数参数。
NativeType Call<type>Method(JNIEnv *env, jobject obj,
jmethodID methodID, ...);


NativeType Call<type>MethodA(JNIEnv *env, jobject obj,
jmethodID methodID, const jvalue *args);


NativeType Call<type>MethodV(JNIEnv *env, jobject obj,
jmethodID methodID, va_list args);
Call<type>Method Routine Name Native Type
CallVoidMethod() void
CallVoidMethodA()
CallVoidMethodV()
CallObjectMethod() jobject
CallObjectMethodA()
CallObjectMethodV()
CallBooleanMethod() jboolean
CallBooleanMethodA()
CallBooleanMethodV()
CallByteMethod() jbyte
CallByteMethodA()
CallByteMethodV()
CallCharMethod() jchar
CallCharMethodA()
CallCharMethodV()
CallShortMethod() jshort
CallShortMethodA()
CallShortMethodV()
CallIntMethod() jint
CallIntMethodA()
CallIntMethodV()
CallLongMethod() jlong
CallLongMethodA()
CallLongMethodV()
CallFloatMethod() jfloat
CallFloatMethodA()
CallFloatMethodV()
CallDoubleMethod() jdouble
CallDoubleMethodA()
CallDoubleMethodV()
2.1.3 CallNonvirtual<type>Method Routines

CallNonvirtual<type>Method,CallNonvirtual<type>MethodA和CallNonvirtual<type>MethodV函数系列用来调用实例方法。其中<type>所调用函数的返回值类型。

NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, ...);

NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, const jvalue *args);

NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);
2.1.4 示例
public class MethodCall {
    static {
        System.loadLibrary("jnitest");
    }

    private void callback() {
        System.out.println("In Java.");
    }

    public native void nativeMethod();
}

JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_MethodCall_nativeMethod
        (JNIEnv *env, jobject obj) {
    jclass clazz;
    jmethodID mid;

    clazz = env->GetObjectClass(obj);
    if (clazz == nullptr) {
        return;
    }
    mid = env->GetMethodID(clazz, "callback", "()V");
    if (mid == nullptr) {
        return;
    }
    env->CallVoidMethod(obj,mid);
}
2.2 访问类方法
2.2.1 GetStaticMethodID

通过指定类方法的名字和签名,获取类方法ID。

jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
2.2.2 CallStatic<type>Method Routines

CallStatic<type>Method,CallStatic<type>MethodA和CallStatic<type>MethodV函数系列用来调用类方法。

NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz,
jmethodID methodID, ...);

NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz,
jmethodID methodID, jvalue *args);

NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);
CallStatic<type>Method Routine Name Native Type
CallStaticVoidMethod() void
CallStaticVoidMethodA()
CallStaticVoidMethodV()
CallStaticObjectMethod() jobject
CallStaticObjectMethodA()
CallStaticObjectMethodV()
CallStaticBooleanMethod() jboolean
CallStaticBooleanMethodA()
CallStaticBooleanMethodV()
CallStaticByteMethod() jbyte
CallStaticByteMethodA()
CallStaticByteMethodV()
CallStaticCharMethod() jchar
CallStaticCharMethodA()
CallStaticCharMethodV()
CallStaticShortMethod() jshort
CallStaticShortMethodA()
CallStaticShortMethodV()
CallStaticIntMethod() jint
CallStaticIntMethodA()
CallStaticIntMethodV()
CallStaticLongMethod() jlong
CallStaticLongMethodA()
CallStaticLongMethodV()
CallStaticFloatMethod() jfloat
CallStaticFloatMethodA()
CallStaticFloatMethodV()
CallStaticDoubleMethod() jdouble
CallStaticDoubleMethodA()
CallStaticDoubleMethodV()
2.2.3 示例
public class MethodCall {
    static {
        System.loadLibrary("jnitest");
    }

    private static void callbackV2() {
        System.out.println("Static In Java.");
    }

    public native void staticNativeCall();
}

JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_MethodCall_staticNativeCall
        (JNIEnv *env, jobject obj) {
    jclass clazz;
    jmethodID mid;

    clazz = env->GetObjectClass(obj);
    if (clazz == nullptr) {
        return;
    }
    mid = env->GetStaticMethodID(clazz, "callbackV2", "()V");
    if (mid == nullptr) {
        return;
    }
    env->CallStaticVoidMethod(clazz,mid);
}

相关文章

  • 四、JNI-成员和方法

    成员 方法 #1. 成员 Java中成员变量分为普通成员变量和静态成员变量。普通成员变量也称为类实例成员变量,所有...

  • 关于区分类变量、类方法、实例变量、实例方法和默认值

    一、区分类变量、类方法、实例变量、实例方法 1、成员变量和成员方法首先成员变量和成员方法是范围最大的定义:即成员变...

  • 类与对象

    类包括 成员变量 和 成员方法 成员变量:String name; 成员方法 ( 把static去掉 )pu...

  • 做java两年了,构造方法和方法重载还是搞不明白?一文帮你搞定

    成员方法 类成员主要包括成员变量和成员方法。带参数的成员方法带参数的成员方法可以接受用户输入的内容。创建带参数的方...

  • 原型继承

    一、原型判断方法*术语解释:成员=属性+方法实例成员:实例属性和实例方法原型成员:原型对象属性和原型对象方法1、原...

  • java的构造方法和方法重载还是搞不明白吗?看完恍然大悟!

    类成员主要包括成员变量和成员方法。 带参数的成员方法 带参数的成员方法可以接受用户输入的内容。创建带参数的方法时定...

  • static 关键字

    static 关键字主要有以下四种使用场景: 修饰成员变量和成员方法: 被 static 修饰的成员属于类,不属于...

  • static关键字

    static表示静态的意思,用来修饰成员变量和成员方法,也可以修饰代码块被static修饰的成员变量和成员方法独立...

  • 静态成员和实例成员

    静态成员定义在构造函数上面的成员(属性和方法) 实例成员定义在实例对象上面的成员(属性和方法) 建议 代码示例

  • iOS 类方法和成员方法

    iOS 类方法和成员方法 类方法 静态方法,在类编译时在内存中创建,常驻内存,适用于,不需要访问该类成员变量的时候...

网友评论

      本文标题:四、JNI-成员和方法

      本文链接:https://www.haomeiwen.com/subject/loxqhltx.html