You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:50:27