【详解】JNI(Java Native Interface)(一)

前言:html

  一提到JNI,多数编程者会下意识地感觉到一种没法言喻的恐惧。它给人的第一感受就是"难",由于它不是单纯地在JVM环境内操做Java代码,而是跳出虚拟机与其余编程语言进行交互。java

  你可能至今还没据说过这个技术,可是若是你是一个源码爱好者,或者有翻阅过JDK的一些源码,那你必定有接触过native方法。你是否由于查阅源码直到native方法戛然而止,但又因为它的空方法体,而对底层原理不知因此? 本文就带让你了解JNI。并经过一些案例来本身实现JNI的交互。编程

什么是JNI?windows

  JNI 全称 Java Native Interface。Java本地方法接口,它是Java语言容许Java代码与C、C++代码交互的标准机制。维基百科是这样解释的:“当应用没法彻底用Java编程语言实现的时候,(例如,标准Java类库不支持的特定平台特性或者程序库时),JNI使得编程者可以编写native方法来处理这种状况”。这就意味着,在一个Java应用程序中,咱们可使用咱们须要的C++类库,而且直接与Java代码交互,并且在能够被调用的C++程序内,反过来调用Java方法(回调函数)。编程语言

 

JNI的优势函数

  (1)JNI使得一些"过程"无需在Java中实现。例如,硬件敏感的,或者直接与操做系统API关联的命令。工具

  (2)因为使用底层的库,如图形,计算,各类类型的渲染等等,能够提升应用的运行性能。性能

  (3)已经有大量的库已经被实现,编程者可直接使用,不用再自行编写。这里的库指的是用其余编程语言实现的程序库,例如IO流或者线程等底层与OS交互的操做都是由C/C++实现的。spa

 

具体实现原理操作系统

  交互模式如图

  

 

要从Java调用C++函数,你须要进行如下操做: 

  1. 在Java类中建立一个native方法,此方法被本类其余方法调用

        

  2. 建立一个头文件,能够利用javah命令生成。

      在头文件中定义它的签名,以下所示:

  

  接口规范:

  JNIEXPORT <返回类型> JNICALL Java_<包名>_<类名>_<方法名>(JNIEnv*, <原对象引用>,<参数1>..<参数n>)

  • extern "C" 只被C++编译器识别,标明此方法利用C的函数命名协议来编译。
  • JNIEXPORT 是JNI必要的修饰符。
  • 数据类型带有"j"前缀的:jdouble,jobject..等是Java对象或类型在C++中的映射
  • JNIEnv* 指向JNI 环境,能够利用其调用全部JNI函数
  • jobject 引用当前Java对象

  3. 建立一个源文件,实现头文件中定义的接口。实现内容就是Java代码调用的C/C++代码。

  4. 编译头文件和源文件生成C/C++动态连接库 .so/.dll 文件

  5. 此native方法所在类,加载动态连接库。由于加载连接库要在执行native方法以前,因此此加载过程通常放在静态初始化块内执行。

   

  或

  

  总结一下,从Java代码中调用C/C++代码的流程

  (1)建立一个有native标识的方法,而且从其余Java方法调用它

  (2)Java编译器生成字节码

  (3)C/C++ 编译器生成动态库  .so文件(Linux)或 .dll文件(Windows)

  (4)运行程序,执行字节码

  (5)执行到loadLibary或load调用的时候,添加一个 .so文件到这个进程中

  (6)执行到native方法的时候,经过方法签名,在已打开的.so文件中进行搜索。

  (7)若是连接库内有对应方法,就会被执行,不然程序崩溃

  注:因为windows没找到生成动态连接库的工具,又不想安装C/C++开发环境,故如下案例都在以CentOS为操做系统的虚拟机内运行

  案例一:从Java调用C代码输出Hello World   

  此案例全部生成的全部文件以下:

  

  (1)建立JNI文件夹,建立Java文件以下:

  

  这里,咱们定义了一个native方法,是个空方法体,咱们在主函数内对其进行调用。

  注:这里使用的是System.load从绝对路径引用动态连接库,固然也可使用loadLibrary方法,其是从java.library.path对应路径下搜索对应名称的库文件并加载。

  (2)编译HelloJNI.java文件,生成类文件

  

  (3)利用JDK提供的JNI命令工具,javah生成 .h头文件。

  

  注:发现Linux环境下,javah竟然不能从当前文件夹扫描到类文件,须要指定类路径 其中 -cp 就是-classpath

  如下是利用javah生成的头文件。

  

  (4)建立HelloJNI.c文件,编写实现体

  

  (5)利用gcc生成动态连接库,注意咱们这里有引用到jni.h这个头文件,此文件由JDK提供,另外jni.h还引用了jni_md.h这个文件。必须引入这两个头文件,才能经过编译。

  两个文件的所在地,本人JDK的安装路径在/usr/java下,每一个人可能都不同。

  

  

  在gcc命令内经过指定( -I 路径 )引入库所在的目录,利用前面前面的头文件和源文件编译成动态连接库 hello.so

  

  

  (6)运行java程序

  

  由图可知,咱们成功调用了C的代码

相关文章
相关标签/搜索