在上一篇中介绍了JNI 回调实例方法与静态方法。本文是JNI系列的第八篇,介绍JNI中的如何在Native代码
中调用当前类的父类的方法。
系列文章的大纲如下:
如果我们需要在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,关注获取第一手资料。
本文完。