php native interface,【详解】JNI(Java Native Interface)(一)

前言:

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

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

什么是JNI?

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++实现的。

具体实现原理

交互模式如图

12386

要从Java调用C++函数,你需要进行以下操作:

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

12386

2. 创建一个头文件,可以利用javah命令生成。

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

12386

接口规范:

JNIEXPORT JNICALL Java___(JNIEnv*, ,..)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方法之前,所以此加载过程一般放在静态初始化块内执行。

12386

12386

总结一下,从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

此案例所有生成的所有文件如下:

12386

(1)创建JNI文件夹,创建Java文件如下:

12386

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

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

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

12386

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

12386

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

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

12386

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

12386

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

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

12386

12386

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

12386

12386

(6)运行java程序

12386

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值