首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Java JNI 静态注册和动态注册

  • 24-12-14 15:44
  • 2205
  • 8421
juejin.cn

Java JNI 静态注册和动态注册

  • 静态注册是指 Java native 方法和对应的本地函数按照预先定义好的命名规则来建立关联,实现了 Java native 方法与本地函数实现的绑定,这些函数会在 Java 类加载时被静态注册到 JVM 中,以确保 JVM 能够正确地找到对应的函数
  • 动态注册是通过提供一个 Java native 方法和本地函数一一对应的映射表,然后在 JNI_OnLoad 回调里将映射表注册给 JVM,这样一来 JVM 就可以用这个映射表来调用相应的函数了,而不必像静态注册那样通过函数名去查找需要调用的函数,所以本地函数名不需要遵循特定命名规则
  • PS:在 JNI 中静态注册和静态库之间没有直接的关系,无论是静态注册还是动态注册都可以生成动态库(.so文件)或者静态库(.a 文件)
java
代码解读
复制代码
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_类全限定名_方法名 的格式(类全限定名中的 . 需要用 _ 替换)命名规范
cpp
代码解读
复制代码
extern "C" JNIEXPORT jstring JNICALL Java_com_louis_myjni_MainActivity_stringFromJNI( JNIEnv* env, //JNIEnv 指的是当前 java 环境,利用 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 相关函数和都是使用的动态注册
cpp
代码解读
复制代码
//定义本地函数,函数名任意 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; //获取与当前线程关联的 JNIEnv 指针 if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { LOGE("获取 JNIEnv 环境失败"); 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 函数名暴露,所以存在一定的安全隐患
  • 动态注册灵活性高,不依赖于固定的命名规则,不过需要自行注册手动关联,可以做到在运行时根据条件选择不同的实现,更适合复杂项目
注:本文转载自juejin.cn的louisgeek的文章"https://juejin.cn/post/7447771974312820747"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

140
Android
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top