当前位置: 首页 > news >正文

JNI 本地方法调用 Java 静态方法 和 实例方法对比;通过本地方法创建 Java 对象;本地方法访问 Java 数组元素;本地方法错误返回给 Java

以下是针对 Java JNI 的详细代码示例和对比分析:


一、调用 Java 静态方法 vs 实例方法

Java 示例类
public class JNIExample {
    public static void staticMethod(int value) {
        System.out.println("Static Method: " + value);
    }

    public void instanceMethod(String msg) {
        System.out.println("Instance Method: " + msg);
    }
}
JNI 实现代码
extern "C" JNIEXPORT void JNICALL Java_JNIExample_callMethods(JNIEnv *env, jobject obj) {
    // 1. 调用静态方法
    jclass cls = env->GetObjectClass(obj); // 或直接 FindClass("JNIExample")
    jmethodID staticMid = env->GetStaticMethodID(cls, "staticMethod", "(I)V");
    env->CallStaticVoidMethod(cls, staticMid, 42); // 参数为 int 42

    // 2. 调用实例方法
    jmethodID instanceMid = env->GetMethodID(cls, "instanceMethod", "(Ljava/lang/String;)V");
    jstring jmsg = env->NewStringUTF("Hello from JNI");
    env->CallVoidMethod(obj, instanceMid, jmsg); // 需要对象实例 obj
}
对比表格
对比项静态方法调用实例方法调用
方法ID获取GetStaticMethodIDGetMethodID
调用函数CallStaticVoidMethodCallVoidMethod
参数需要类对象(cls需要对象实例(obj
适用场景调用类的静态方法调用特定对象的实例方法
注意事项无需对象实例必须确保对象实例有效

二、通过本地方法创建 Java 对象

Java 类(带构造器)
public class Person {
    public String name;
    public Person(String name) {
        this.name = name;
    }
}
JNI 实现代码
extern "C" JNIEXPORT jobject JNICALL Java_JNIExample_createObject(JNIEnv *env, jobject obj) {
    // 1. 获取类对象和构造方法ID
    jclass personCls = env->FindClass("Person");
    jmethodID constructor = env->GetMethodID(personCls, "<init>", "(Ljava/lang/String;)V");

    // 2. 创建新对象并调用构造器
    jstring jname = env->NewStringUTF("Alice");
    jobject personObj = env->NewObject(personCls, constructor, jname);

    return personObj; // 返回新对象给Java层
}

三、访问 Java 数组元素

Java 示例
public class JNIArrayExample {
    public native void processArray(int[] arr);
}
JNI 实现代码
extern "C" JNIEXPORT void JNICALL Java_JNIArrayExample_processArray(JNIEnv *env, jobject obj, jintArray arr) {
    // 1. 获取数组长度和元素指针
    jsize length = env->GetArrayLength(arr);
    jint* elements = env->GetIntArrayElements(arr, nullptr);

    // 2. 访问/修改元素(示例:打印所有元素)
    for (jsize i = 0; i < length; i++) {
        printf("Element %d: %d\n", i, elements[i]);
    }

    // 3. 释放资源(避免内存泄漏)
    env->ReleaseIntArrayElements(arr, elements, 0); // 0表示不复制回Java数组
}

四、JNI 异常处理(错误返回给 Java)

Java 示例
public class JNIExceptionExample {
    public native void riskyMethod();
}
JNI 实现代码
extern "C" JNIEXPORT void JNICALL Java_JNIExceptionExample_riskyMethod(JNIEnv *env, jobject obj) {
    // 1. 检查异常发生
    if (/* 某些错误条件 */) {
        // 2. 抛出Java异常(需提前注册异常类)
        jclass exceptionCls = env->FindClass("java/lang/RuntimeException");
        env->ThrowNew(exceptionCls, "JNI Error: Something went wrong!");
    }
}
Java 异常捕获
try {
    JNIExceptionExample example = new JNIExceptionExample();
    example.riskyMethod();
} catch (RuntimeException e) {
    System.out.println("Caught exception: " + e.getMessage());
}

关键总结

操作类型JNI 函数/方法注意事项
调用静态方法GetStaticMethodID + CallStatic...需要类对象 cls
调用实例方法GetMethodID + Call...需要对象实例 obj
创建对象GetMethodID(构造器) + NewObject构造器方法名是 <init>
访问数组GetIntArrayElements必须调用 Release... 避免内存泄漏
抛出异常ThrowNew需要提前查找异常类 FindClass

通过以上示例和对比,可以清晰理解 JNI 中不同操作的实现方式和关键差异。

相关文章:

  • Linux Shell 基础操作笔记
  • charles接口测试(断点测试)
  • 本人设计的最完全的光压发电机模型
  • 05_循环结构三目运算符
  • Spring MVC 配置详解与入门案例
  • SpringBoot 面试八股文
  • 基于@Scheduled注解(静态配置)实现定时任务
  • SQL调优
  • 搭建PG库和安装pgvector、pgRouting插件
  • uniapp 微信小程序图片下载保存功能
  • TypeScript 泛型 < T > 从入门到精通
  • 可视化图解算法:删除有序(排序)链表中重复的元素
  • 基于AOP注解+Redisson实现Cache-Aside缓存模式实战
  • 春日焕新居:约克VRF中央空调,科技赋能,带你开启健康呼吸新时代
  • 力扣题目分享:只出现1次的数字I II III(位运算版)
  • 宝塔docker flarum默认登录账号密码,crazymax/flarum镜像默认登录账号密码
  • 蓝桥杯算法题分享(二)
  • 从 Copilot 到垂直工具:AI 编程的 “专精特新“ 进化论
  • 用python写网络爬虫
  • 如何用Spring AI构建MCP Client-Server架构
  • 牛市早报|央行:加力支持提振消费、稳定外贸等领域,用好用足存量增量政策
  • 失智老人有两个儿子却欠费住养老院两年多,法检合力指定监护人
  • 习近平向2025年上海合作组织减贫和可持续发展论坛致贺信
  • 国家话剧院上海演出季7月重启,《大宅门》等5部大戏来沪
  • 中美博弈新阶段,这个“热带中国”火了
  • 魔都眼|邮轮港国际帆船赛启动,120名中外选手展开角逐