上篇文章讲述了如何Java调用C接口的方法:

  • 在Java层定义native关键字函数
  • 在c/c++层创建Java_packagename_classname_methodname函数

 本文讲述另一种灵活的方法【上文的方法显然不够灵活。JNI当然早就想到了】

  • 在Java层定义native关键字函数
  • RegisterNative【手工自己去映射Java层定义的函数到底调用的是c层的那个api接口】

映射表:

typed struct{

     const char* name;

     const char* signature;

     void * fnPtr;

}JNINativeMethod;

这就是一个结构体。其中的name就是java层定义的native标注的方法名.signature就是一个符号,代表我们传入的那个参数是什么样子的,字面意思就是签名【方法的签名(java概念)】这个参数不能是简单的int、float等普通的数据类型.它是一个字符串且是一个有规格的字符串。【下文介绍signature】signature就是标注输入参数和输出参数的。fnPtr就是真正要映射到c/c++层的具体的api,这就是函数指针,在java层去调用native定义的名字的时候通过java虚拟机就会找到这个映射表,通过name搜索到具体的函数fnPtr,最终去调到这个函数去执行具体的逻辑。


注册Native方法的最佳时机:

有了这个fnPtr函数,到什么时候去调用呢。JNI帮我们设计了如下接口:

jint JNI_OnLoad(JavaVM *vm,void* reserved)

这个函数在库被加载的会触发。当我们的库被加载到虚拟机后它会自动回调这个函数JNI_OnLoad。在这个函数里就将我们需要的native方法全部注册进去。注册之后,在下面的逻辑里当java层去访问相应的api的时候就直接通过java虚拟机映射到c/c++层的api,并具体去做c/c++层的逻辑处理,当有结果的时候再返回给java层。

还有个

jint JNI_OnUnLoad(JavaVM *vm,void* reserved)

当我们的动态库被卸载的时候会触发这个函数。在这个函数里可以做一些资源的释放。


具体示例Demo:

Java报signature错误 java signature类_c++

Java报signature错误 java signature类_Java报signature错误_02

 

Java报signature错误 java signature类_Java报signature错误_03

Java报signature错误 java signature类_java_04

 

第一次写的时候有点多的代码。但是再在java中再加一个native标识的方法,再native层写一下映射关系就ok.