JNI 调用Java中的super.method()

JNI 调用Java中的super.method()

在上一篇中介绍了JNI 回调实例方法与静态方法。本文是JNI系列的第八篇,介绍JNI中的如何在Native代码
中调用当前类的父类的方法。

系列文章的大纲如下:

JNI 调用Java中的super.method()

如果我们需要在JNI中调用一个对象的父类的方法,怎么来实现呢?

JNI为我们提供了这样的入口,一起来看一下吧。

获取父类:

// 如果clazz是除了jclass这个类型之外的对象,返回clazz的父类;
// 如果clazz是jclass类型的对象,或者是interface类型,返回NULL
jclass GetSuperclass(JNIEnv *env, jclass clazz);

调用super类的方法:

// 调用对象obj的父类clazz的方法ID为methodID的方法
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);

其中:

CallNonvirtual<type>Method Routines NativeType
CallNonvirtualVoidMethod() jobject
CallNonvirtualObjectMethod() jobject
CallNonvirtualBooleanMethod() jboolean
CallNonvirtualByteMethod() jbyte
CallNonvirtualCharMethod() jchar
CallNonvirtualShortMethod() jshort
CallNonvirtualIntMethod() jint
CallNonvirtualLongMethod() jlong
CallNonvirtualFloatMethod() jfloat
CallNonvirtualDoubleMethod() jdouble

CallNonvirtual<type>Method()CallNonvirtual<type>MethodA()CallNonvirtual<type>MethodV()之前的区别在于传递参数的形式上的区别。
具体参见下面的实例。

通过下面的实例来加深一下理解。

实例

我们来看一个实例。

这次依然使用一个新文件来说明:

package myjni.nonvirtual;

class A {
    public void doSomething() {
        System.out.println("A.doSomething " + this.getClass().getName());
    }
}

class B extends A {
    public void doSomething() {
        System.out.println("B.doSomething " + this.getClass().getName());
    }
}

public class Test {
    static {
        System.loadLibrary("hello");
    }

    public static native void jniTest(B b);

    public static void main(String[] args) {
        B obj = new B();
        jniTest(obj);
    }
}

如果还不清楚如果生成头文件请参考JNI简介

类B继承类A,在类B中重写方法doSomething。测试的方法是jniTest传递类型B的对象,我们使用它去调用其父类的方法doSomething

生成头文件myjni_nonvirtual_Test.h的签名为:

/*
 * Class:     myjni_nonvirtual_Test
 * Method:    jniTest
 * Signature: (Lmyjni/nonvirtual/B;)V
 */
JNIEXPORT void JNICALL Java_myjni_nonvirtual_Test_jniTest
  (JNIEnv *, jclass, jobject);

实现函数Java_myjni_nonvirtual_Test_jniTest

JNIEXPORT void JNICALL Java_myjni_nonvirtual_Test_jniTest(JNIEnv *env, jclass clazz, jobject obj) {
  // Call obj.doSomething()
  jclass bClazz = env->GetObjectClass(obj);
  if (bClazz == nullptr) {
    std::cout << "get obj class failed\n";
    return;
  }

  jmethodID midDoSomething = env->GetMethodID(bClazz, "doSomething", "()V");
  if (midDoSomething == nullptr) {
    std::cout << "get method failed\n";
    return;
  }

  env->CallVoidMethod(obj, midDoSomething);

  // Call obj.super().doSomething()
  jclass parentClass = env->GetSuperclass(bClazz);
  if (parentClass == nullptr) {
    std::cout << "get super class failed\n";
    return;
  }

  jmethodID midDoSomethingInParent = env->GetMethodID(parentClass, "doSomething", "()V");
  if (midDoSomethingInParent == nullptr) {
    std::cout << "get method failed\n";
    return;
  }
  env->CallNonvirtualVoidMethod(obj, parentClass, midDoSomethingInParent);
}

编译生成动态库,并运行Java程序得到输出:

B.doSomething myjni.nonvirtual.B
A.doSomething myjni.nonvirtual.B

vx搜:极客Furzoom,关注获取第一手资料。

本文完。

上一篇:Java反射基础方法使用


下一篇:B_第01章:Java基础