JNI系列教程一——入门
1.1 背景
和很多语言类似,java也提供了调用原生代码的功能,这门技术叫做JNI。有了JNI,可以在付出更小的代价的前提下,复用大量已经写好的C/C++库,当然一般用JNI的目的还是由于java在处理计算密集型(比如说非对称运算)的操作时有时会力不从心。
从结构上来看JNI是一个中间层,具体的调用步骤是这个样子的:java->JNI->C/C++。
本文源地址https://blog.whyun.com/posts/jni 转载请注明出处
1.2 准备活动
1.2.1 编写java代码
代码 1.2.1.1
注意到我们在类FirstDemo
中定义了两个成员函数都没有函数体,且都加了关键字native
声明,如果函数写成这样,则代表当前函数需要调用底层C/C++代码。注意System.loadLibrary
这句话,java中使用这个函数来加载动态库,windows平台下运行此段代码要保证firstdemo.dll
存在环境变量%path%
中,linux平台下要保证libfirstdemo.so
存在环境变量$LD_LIBRARY_PATH
中。
其实java在
loadLibrary
的时候,是读取的系统变量java.library.path
来搜寻动态库位置的,你可以用System.getProperty("java.library.path")
来输出这个变量的内容。只不过在windows中会把环境变量%path%
的内容加入到这个变量中,在linux中会把环境变量$LD_LIBRARY_PATH
加入到这个变量中。在我的一台linux上打印java.library.path
,会输入如下内容:/usr/jdk1.6.0_45/jre/lib/i386/server:/usr/jdk1.6.0_45/jre/lib/i386: /usr/jdk1.6.0_45/jre/../lib/i386: /home/username/lib::/usr/java/packages/lib/i386 :/lib:/usr/lib
其中/home/username/lib:
是从环境变量$LD_LIBRARY_PATH
读取的。不推荐将生成的动态库放置到系统目录中,首先是不一定有管理员权限,其次会导致系统库目录下的文件过多,不易管理。
1.2.2 生成头文件
本文用到的项目源码在文后给出,项目的目录结构如下:
图1.2.2 项目目录结构
其中目录out/production
为我们的class文件生成的目录,在命令行下进入该目录,运行如下命令javah com.whyun.jni.chapter1.FirstDemo
,运行成功之后则在运行命令行的目录下生成文件com_whyun_jni_chapter1_FirstDemo.h
,用文本编辑器打开这个头文件,会显示如下内容:
代码 1.2.1
1.3 编译运行
为了简化在windows和linux下配置编译步骤,我们先在操作系统中配置两个环境变量,在windows上将JAVA_HOME
配置为JDK的安装路径,很多情况下这个环境变量在配置JDK编译环境的时候已经配置过,可以通过echo %JAVA_HOME%
的输出来判断之前是否已经配置过;同理我们在linux上也配置环境变量JAVA_HOME
(通过运行echo $JAVA_HOME
来检测是否存在)。同时我们在windows上将目录d:\lib
加入环境变量PATH
中,在linux上将/opt/lib
加入环境变量LD_LIBRARY_PATH
中。
1.3.1 windows编译环境配置
windows下需要安装visual studio(简称vs)环境来完成C/C++编译,vs 有professional、ultimate和Express三个版本,前两者收费,我们使用免费的Express就够用了。我电脑上装的是vs express for desktop版本。
打开vs,新建项目,选择Visual C++,然后选择Empty Project,输入项目名firstdemo
,点击确定。
接着设置项目属性,右击项目,然后选择properties,在Configuration Properties->General->Project Defaults->Configuration Type中,选择Dynamic Library (.dll)
。然后在Configuration Properties->VC++ Directories->General->Include Directories中添加两个路径:$(JAVA_HOME)\include
和$(JAVA_HOME)\include\win32
。
最后编写c代码,在vs中新建源代码的时候,默认是cpp后缀,我们这里建一个c后缀的文件,因为我的编写习惯是c语法。
代码1.3.1 firstdemo.c
注意我们引用了之前的com_whyun_jni_chapter1_FirstDemo.h
,我们把它放到firstdemo.c
同一级目录下了。
接着运行编译,产生dll文件,默认情况下会在项目目录Debug文件夹下产生firstdeom.dll,你可以把这个文件夹添加到环境变量PATH中去,也可以写脚本在编译完成之后将dll拷贝到电脑的任何一个PATH路径下,在Configuration Properties->Build Events->Post-Build Event->Command Line中写入如下命令:copy "$(TargetDir)$(TargetName).dll" d:\lib\$(TargetName).dll
。
1.3.2 linux编译
在linux下使用命令行GCC即可,将com_whyun_jni_chapter1_FirstDemo.h
和firstdemo.c
放到同一个目录下,然后运行脚本
1.3.3 运行
运行java代码,最终输出
本文用到的源代码可以从https://gitlab.com/yunnysunny/jni 获得到