关于JNI与抽象类的两项技术问询
嘿,这两个关于JNI和抽象类的问题挺典型的,我来给你拆解清楚:
问题1:是否可以通过JNI在C++中调用Java抽象方法,本质上利用JNI创建需在Java中继承的抽象类?
首先得明确:抽象类本身无法直接实例化,所以JNI也没办法直接创建抽象类的对象。但如果你的Java代码里有继承了这个抽象类的具体子类,并且实现了抽象方法,那JNI完全可以拿到这个子类的实例,进而调用对应的抽象方法(因为子类已经把方法实现了)。
举个简单的例子:
首先在Java里定义抽象类和它的具体子类:
// 抽象类 public abstract class MyAbstractBase { public abstract void executeTask(); } // 实现抽象类的具体子类 public class MyConcreteImpl extends MyAbstractBase { @Override public void executeTask() { System.out.println("执行Java侧的具体任务逻辑"); } }
然后在C++的JNI代码里,你可以通过JNI API获取MyConcreteImpl的实例(比如通过FindClass、GetMethodID、NewObject创建实例,或者从Java侧传入实例),然后调用executeTask方法:
JNIEXPORT void JNICALL Java_com_example_MyJNI_callAbstractMethod(JNIEnv *env, jobject obj) { // 找到具体子类的类 jclass concreteCls = env->FindClass("com/example/MyConcreteImpl"); // 获取子类的无参构造方法 jmethodID constructor = env->GetMethodID(concreteCls, "<init>", "()V"); // 创建子类实例 jobject concreteObj = env->NewObject(concreteCls, constructor); // 找到抽象方法的MethodID(注意:这里用父类的类或者子类的类都可以,因为方法是继承来的) jclass abstractCls = env->FindClass("com/example/MyAbstractBase"); jmethodID executeMethod = env->GetMethodID(abstractCls, "executeTask", "()V"); // 调用方法 env->CallVoidMethod(concreteObj, executeMethod); // 释放局部引用(避免内存泄漏) env->DeleteLocalRef(concreteCls); env->DeleteLocalRef(concreteObj); env->DeleteLocalRef(abstractCls); }
总结一下:JNI不能直接“创建需要Java继承的抽象类”,但可以调用抽象类的具体子类实现的抽象方法——核心是你必须有一个已经实现了抽象方法的Java子类实例。
问题2:是否可以用Java方法重写Native JNI方法?
当然可以!Java里的native方法和普通方法一样,可以被子类重写。重写后,当你调用该方法时,会优先执行Java侧的重写实现,而不是原来的Native代码。
举个例子:
首先定义一个带有native方法的父类:
public class NativeBaseClass { // 声明native方法 public native void doNativeWork(); }
然后子类重写这个native方法:
public class JavaOverrideClass extends NativeBaseClass { @Override public void doNativeWork() { System.out.println("我是Java侧重写的方法,替代了原来的Native逻辑"); // 如果还想调用原来的Native实现,可以用super // super.doNativeWork(); } }
这时候,如果你创建JavaOverrideClass的实例并调用doNativeWork(),执行的就是Java侧的重写代码。哪怕是在Native代码里通过JNI调用这个实例的方法,也会触发Java的重写实现——JNI会根据对象的实际类型动态分发到对应的方法。
另外补充一点:如果在重写的Java方法里还想调用原来的Native实现,直接用super.doNativeWork()就可以,和普通方法的重写逻辑完全一致。
内容的提问来源于stack exchange,提问作者Stephanus Tavilrond

