浅析Java中JNI静态注册和动态注册

 更新时间:2024年12月16日 08:35:28   作者:louisgeek  
这篇文章主要为大家详细介绍了Java中JNI静态注册和动态注册的相关知识,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下

静态注册是指 Java native 方法和对应的本地函数按照预先定义好的命名规则来建立关联,实现了 Java native 方法与本地函数实现的绑定,这些函数会在 Java 类加载时被静态注册到 JVM 中,以确保 JVM 能够正确地找到对应的函数

动态注册是通过提供一个 Java native 方法和本地函数一一对应的映射表,然后在 JNI_OnLoad 回调里将映射表注册给 JVM,这样一来 JVM 就可以用这个映射表来调用相应的函数了,而不必像静态注册那样通过函数名去查找需要调用的函数,所以本地函数名不需要遵循特定命名规则

PS:在 JNI 中静态注册和静态库之间没有直接的关系,无论是静态注册还是动态注册都可以生成动态库(.so文件)或者静态库(.a 文件)

public class MainActivity extends AppCompatActivity {
    // Used to load the 'myjni' library on application startup.
    static {
        System.loadLibrary("myjni");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //
        String str = stringFromJNI();
        Log.e("TAG", "onCreate: str="+str);
    }
    /**
     * A native method that is implemented by the 'myjni' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI(); //java native 方法
}

静态注册

本地函数的函数名需要遵循 Java_类全限定名_方法名 的格式(类全限定名中的 . 需要用 _ 替换)命名规范

extern "C" JNIEXPORT jstring JNICALL
Java_com_louis_myjni_MainActivity_stringFromJNI(
        JNIEnv* env,           //JNIEnv 指的是当前 JNI 环境,利用 JNIEnv 可以操作 java 层代码
        jobject /* this */) {  //jobject 指的是 JNI 函数对应的 java native 方法所在类的实例对象,如果 native 方法是 static 的话则类型就需要改成 jclass,代表的是类对象
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

动态注册

  • 当 Java 层调用 System.loadLibrary 方法时,JNI_OnLoad 函数会在库被加载到 Java 虚拟机时调用
  • PS:比如 Android 系统的 JNI 函数和 FFmpeg 相关函数和都是使用的动态注册
//定义本地函数,函数名任意
jstring stringFromJNI_JNI_OnLoad(JNIEnv *env, jobject/* this */) {
    std::string hello = "Hello from C++  stringFromJNI_JNI_OnLoad";
    return env->NewStringUTF(hello.c_str());
}

//定义一个 JNINativeMethod 结构体数组(映射表),结构体包含 Java 方法名、方法签名(方法描述符)以及对应关联的本地函数的指针
JNINativeMethod nativeMethods[] = {
    //stringFromJNI 对应 Java native 方法,stringFromJNI_JNI_OnLoad 对应本地函数
    {"stringFromJNI", "()Ljava/lang/String;", (jstring *) stringFromJNI_JNI_OnLoad}
};

//Java 调用 System.loadLibrary 时此 JNI_OnLoad 函数就会执行
//JavaVM *vm 参数是一个指向 Java 虚拟机的指针,通过这个指针可以访问 JVM 的功能
//void *reserved 是一个保留参数,通常不使用
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    //获取与当前线程关联的 JNI 环境
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGE("获取 JNI 环境失败");
        return JNI_ERR;
    }
    //通过类的全限定名来查找并加载一个类,返回一个指向该类的 jclass 引用
    jclass clazz = env->FindClass("com/louis/myjni/MainActivity");
    if (clazz == NULL) {
        LOGE("获取 jclass 失败");
        return JNI_ERR;
    }
    //计算 arr 数组的长度 int length = sizeof(arr) / sizeof(arr[0]);
    int nMethods = sizeof(nativeMethods) / sizeof(nativeMethods[0]);
    //参数 nMethods 指定数组中 NativeMethod 的数量
    if (env->RegisterNatives(clazz, nativeMethods, nMethods) != JNI_OK) {
        LOGE("注册本地函数失败");
        return JNI_ERR;
    }
    LOGE("注册成功");
    return JNI_VERSION_1_6; //返回当前支持的 JNI 版本号
}

总结

静态注册简单易用,函数必须要有类似 JNIEXPORT jstring JNICALL 这样的相关声明,而且函数名必须要按照 JNI 的命名规则去命名,由于 JNI 函数名暴露,所以存在一定的安全隐患

动态注册灵活性高,不依赖于固定的命名规则,不过需要自行注册手动关联,可以做到在运行时根据条件选择不同的实现,更适合复杂项目

到此这篇关于浅析Java中JNI静态注册和动态注册的文章就介绍到这了,更多相关Java JNI静态注册和动态注册内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java语法之 Java 的多态、抽象类和接口

    Java语法之 Java 的多态、抽象类和接口

    上节介绍了 Java 基础语法之解析 Java 的包和继承,如果这类知识有点疑惑的小伙伴,可以去 Java 的包和继承 这章看看,或许可以帮你解决一些疑惑哟!今天这篇文章我们将讲解的是 Java 的多态、抽象类和接口,感兴趣的小伙伴可以参考下面文章的具体内容
    2021-09-09
  • Java synchronized同步关键字工作原理

    Java synchronized同步关键字工作原理

    synchronized作为Java程序员最常用同步工具,很多人却对它的用法和实现原理一知半解,以至于还有不少人认为synchronized是重量级锁,性能较差,尽量少用。但不可否认的是synchronized依然是并发首选工具,本文就来详细讲讲
    2023-02-02
  • kafka内外网访问配置方式

    kafka内外网访问配置方式

    这篇文章主要介绍了kafka内外网访问配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java 正则,object中两个方法的使用(详解)

    java 正则,object中两个方法的使用(详解)

    下面小编就为大家带来一篇java 正则,object中两个方法的使用(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • spring IOC容器的Bean管理XML自动装配过程

    spring IOC容器的Bean管理XML自动装配过程

    这篇文章主要为大家介绍了spring IOC容器Bean管理基于XML的自动装配过程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • java实现上传文件到服务器和客户端

    java实现上传文件到服务器和客户端

    这篇文章主要为大家详细介绍了java实现上传文件到服务器和客户端,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • Java Red5服务器实现流媒体视频播放

    Java Red5服务器实现流媒体视频播放

    这篇文章主要介绍了Java Red5服务器实现流媒体视频播放,对视频播放感兴趣的同学,可以参考下
    2021-04-04
  • Spring中Bean扫描原理详情

    Spring中Bean扫描原理详情

    这篇文章主要介绍了Spring中Bean扫描原理详情,文章为荣啊主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • Mybatis resultMap标签继承、复用、嵌套方式

    Mybatis resultMap标签继承、复用、嵌套方式

    这篇文章主要介绍了Mybatis resultMap标签继承、复用、嵌套方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • java教学笔记之对象的创建与销毁

    java教学笔记之对象的创建与销毁

    面向对象的编程语言使程序能够直观的反应客观世界的本来面目,并且使软件开发人员能够运用人类认识事物所采用的一般思维方法进行软件开发,是当今计算机领域中软件开发和应用的主流技术。
    2016-01-01

最新评论