native和static native区别

靳茂
2023-12-01

本文基于Hello JNI
如有疑惑,请看之前几篇文章。

native 与 static native

java中

    public native String helloJni();
    public native static String helloJniStatic();

JNI中

JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_helloJni
  (JNIEnv *, jobject);

JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_helloJniStatic
  (JNIEnv *, jclass);

区别在于第二个参数是jobject还是jclass,和java中static方法属于类而不属于对象一样,static 的native方法属于类,所以第二个参数是jclass而不是jobject。

jobject获取jclass

jclass cls = env->GetObjectClass(jobj);

注意:这里获取到的cls是已有对象的cls。

jclass获取jobject

jmethodID cid = env->GetMethodID(cls, "<init>", "()V");
jobject  jobj = env->NewObject(cls, cid);

注意:这里获取到的jobj已经是一个新的对象。

下面看一组对比Demo

通过jobject获取jclass,并修改对象中的age字段

JNIEXPORT jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_helloJni
  (JNIEnv *env, jobject jobj){
    jclass cls = env->GetObjectClass(jobj);
    //2.获取age的jfieldID 注意用GetStaticFieldID方法
    jfieldID jfid = env->GetStaticFieldID(cls, "age", "I");
    //3.通过jfid获取age的属性值,注意用GetStaticIntField
    jint jage = env->GetStaticIntField(cls, jfid);
    jage += 10;
    //4.修改age的属性值,注意用GetStaticIntField
    env->SetStaticIntField(cls,jfid, jage);
    return env->NewStringUTF("hello jni");
  }

通过jclass获取jobject,然后修改courses数组中第一个元素的值

JNIEXPORT void jclsToJobj(JNIEnv *env, jclass cls) {
    jmethodID cid = env->GetMethodID(cls, "<init>", "()V");
    jobject  jobj = env->NewObject(cls, cid);
    jfieldID fid = env->GetFieldID(cls, "courses", "[Ljava/lang/String;");
    jobjectArray jarray = (jobjectArray) env->GetObjectField(jobj, fid);
    env->SetObjectArrayElement(jarray, 0, env->NewStringUTF("美术"));
}

jstring JNICALL Java_com_test_git_jnidemo_JniUtil_JniDemo_helloJniStatic
        (JNIEnv *env, jclass cls){
    //jclass 转换成 jobject
    jclsToJobj(env, cls);

    //2.获取age的jfieldID 注意用GetStaticFieldID方法
    jfieldID jfid = env->GetStaticFieldID(cls, "age", "I");
    //3.通过jfid获取age的属性值,注意用GetStaticIntField
    jint jage = env->GetStaticIntField(cls, jfid);
    jage += 10;
    //4.修改age的属性值,注意用GetStaticIntField
    env->SetStaticIntField(cls,jfid, jage);
    return env->NewStringUTF("hello jni static");
};

MainActivity.java中运行两个方法

        JniDemo jd = new JniDemo();
        Log.i(TAG, "age修改前: " + jd.age);
        Log.i(TAG, "helloJni->" + jd.helloJni());
        Log.i(TAG, "age修改后: " + jd.age);

        Log.i(TAG, "------------------------------------------");

        Log.i(TAG, "age修改前: " + jd.age);
        Log.i(TAG, "courses修改前: " + jd.courses[0]);
        JniDemo.helloJniStatic();
        Log.i(TAG, "age修改后: " + jd.age);
        Log.i(TAG, "courses修改后: " + jd.courses[0]);

输出结果:

09-26 16:29:27.634 3969-3969/? I/MainActivity-: age修改前: 10
09-26 16:29:27.634 3969-3969/? I/MainActivity-: helloJni->hello jni
09-26 16:29:27.634 3969-3969/? I/MainActivity-: age修改后: 20
09-26 16:29:27.634 3969-3969/? I/MainActivity-: ------------------------------------------
09-26 16:29:27.634 3969-3969/? I/MainActivity-: age修改前: 20
09-26 16:29:27.634 3969-3969/? I/MainActivity-: courses修改前: 语文
09-26 16:29:27.634 3969-3969/? I/MainActivity-: age修改后: 30
09-26 16:29:27.634 3969-3969/? I/MainActivity-: courses修改后: 语文

可见通过jclass获取的jobject是一个新的对象,并不会改变已有对象的值。

 类似资料: