千家信息网

如何进行JNI的使用

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章给大家介绍如何进行JNI的使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java Native Interface(JNI) 是一种使用java语言和原生C/C++语
千家信息网最后更新 2026年10月31日如何进行JNI的使用

这篇文章给大家介绍如何进行JNI的使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

Java Native Interface(JNI) 是一种使用java语言和原生C/C++语言相互调用、混合编程的方法,它允许在Java虚拟机(VM)内运行的Java代码与应用其他编程语言(如C、C++和汇编)编写的应用程序和库进行互操作,它支持从动态链接库中加载代码, 并能使用C/C++的高效的特性。

如果要基本了解JNI的功能与使用,可以阅读Java Native Interface文档https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html

同时,本文将介绍一些在可能在刚开始会注意不到的使用细节。

FindClass找不到类的问题

JNI类名由包名开始, 由'/'分隔,例如

"java/lang/String"

如果要查找的是一个数组类, 类名应为签名形式,所以一个一维String数组的类定义为

"[Ljava/lang/String;"

可以参照https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp9502

但是目前即使全都传入签名形式的类名,FindClass依然会找到对应的类。原因是历史遗留问题,参考https://bugs.openjdk.java.net/browse/JDK-6411605

为了保证正确性,可以在运行class文件时,加参数-Xcheck:jni可以校验类名构造是否规范。

javah生成的函数名不正确的问题

在函数重载和内部类类型作为某个重载函数的参数时,会触发javah生成的函数名不正确的问题,javah会按照JNI的名称解析规则生成JNI函数名,但是JVM在运行时却不会按照这个名字查找函数,因此会出现运行时找不到函数的情况。

参考https://bugs.openjdk.java.net/browse/JDK-8145897

package p;

class A {

static class B {}

static class C {

native static long Foo(B bar);

}

}

运行javah -jni -o jni_libA.h -classpath ./ p.A

预期的输出是:

//Method: Foo

//Signature: (Lp/A$B;)J

JNIEXPORT jlong JNICALLJava_p_A_00024C_Foo__Lp_A_00024B_2

但实际会输出:

//Method: Foo

//Signature: (Lp/A/B;)J

JNIEXPORT jlong JNICALLJava_p_A_00024C_Foo__Lp_A_B_2

内部类B的'$'被忽略。

可选的解决方法有两种:

1. 不把有内部类作为参数的重载函数写入本地方法

2. 在生成方法后手动添加'$'('00024')

JNI中的异常机制

在有异常等待处理时不能调用大多数的JNI方法。要通过函数ExceptionCheck或ExceptionOccurred的返回值预期到有异常并返回,或处理并清除异常。

如果要获得异常的描述,需要找到Throwable类,然后调用它的getMessage "()Ljava/lang/String;"方法,用GetStringUTFChars来获取内容。

很多JNI方法会抛出异常,但有些异常不会被抛出,需要在应当抛出异常的地方添加条件判断,用ThrowNew构造异常,最常见的是java.lang.ArithmeticException与 Java.lang.NullPointerException

JNI中原生数组的取值与赋值

如果想对数组进行写入或读出,GetArrayElements和GetStringChars是非常有用的方式。

GetArrayElements系列函数允许返回一个指向实际元素的指针,或者分配一些内存来拷贝数据。 返回的原始数据的指针在调用释放方法前是保证一直有效的,而且必须手动释放每个获取的数组。同时可以通过传一个非空指针作为isCopy的参数来决定是否拷贝数据。

jbyte* data = env->GetByteArrayElements(array, NULL);

if (data != NULL) {

memcpy(buffer, data, len);

env->ReleaseByteArrayElements(array, data, JNI_ABORT);

}

上面的代码是一个简单的举例,获取了数组,然后拷贝了len长度的byte,最后释放掉数组。

还有一个更简单实现同样功能的方式是

env->GetByteArrayRegion(array, 0, len, buffer);

这种方式有几个好处:

1. 只需要一个JNI调用,减少开销.

2. 不需要对原始数据进行限制或者额外的拷贝数据

3. 减少在某些出错后忘记释放的风险

4. 会在越界时抛出异常

类似的,SetArrayRegion系列方法是将数组中的元素赋值, GetStringRegion或者GetStringUTFRegion是获得String中的字符。

通付盾SDK保护系统应用输入为aar包,通过分析aar结构,将待保护的class文件转换为AST(抽象语法树),对AST进行同态翻译,将其转换为对应的本地代码。本地化的转换规则与AST节点数目一一对应。由于字节码是托管代码,运行于VM中(java代码运行于JVM,安卓字节码运行在Dalvik),对于操作VM内存模型,以及涉及VM特性的行为,如创建对象,抛出异常等操作,本地代码无法表达对应的语义。对于带有这样语义的AST节点,本地代码的翻译遵循JNI调用规范,在确保本地化翻译的正确性的同时兼顾了兼容性。

关于如何进行JNI的使用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

函数 方法 代码 数组 运行 数据 参数 拷贝 类名 问题 内容 同时 指针 方式 语言 参考 应用 生成 原始 元素 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 哈尔滨大商圈互联网科技有限公司 上海卓越科技互联网 工业互联网科技新基建 互联网与科技金融数据 深圳互联网络科技有限公司 互联网科技ppt模板 互联网汽车科技小镇 宁夏众和广鑫互联网科技有限公司 厦门比较好的科技互联网公司 苏州五指互联网络科技有限 燊美集互联网科技有限公司 为客找房互联网科技公司怎么样 启辰互联网科技 皮皮虾互联网科技有限公司 上海创道互联网络科技有限公司 从那以后互联网科技有限公司 湖北辰鑫科技互联网 安徽零酒互联网科技有限公司 绵阳真晨互联网科技有限公司 广州全民伙伴互联网科技有限公司 互联网科技公司排名 链环科技传统企业怎么转型互联网 长沙茂晟互联网科技有限公司 中和天地互联网科技有限公司 互联网科技快讯热点 工业互联网科技成果转化 上海同邻互联网科技有限公司规模 全球科技与互联网公司市值变化 版纳互联网科技选哪家 六子台科技互联网展会
0