前段时间学习了下jni技术,这段时间没再看,发现回头想的时候又要重新看,还是记下来,以备后面还要使用
一、JNI简介
JNI:Java Native Interface,是Java语言提供的一种通用接口,用于Java代码与本地化代码的交互。所谓本地化代码是指直接编译成的与机器相关的二进制代码,而非Java字节码之类的中间代码。Windows下面的可执行文件,DLL等,Linux下面的可执行文件和SO文件等,都是二进制代码。
JNI允许Java语言编写的程序与其他语言编写的程序库(DLL, SO)或可执行文件进行互操作,包括汇编、C、C++。JNI产生的原因在于以下几种需求:
(1). 你的应用程序需要使用系统相关的功能,而Java代码不支持或是难以办到。这个比较典型的是实现托盘图标,有几种现成的方案都是用的JNI做的,名字好像是叫做TrayIcon和StayOnTop。当然啦,如果是用的Java1.6,那就要另当别论了。
(2). 已有其他语言写好的类库或程序,希望Java程序可以使用它们。
(3). 出于更高的性能要求,希望使用汇编或是C/C++语言来实现部分功能。
二、JNI的开发步骤
这里以使用C++编写本地化方法实现为例,开发一个使用JNI的Demo程序,具体步骤如下所示:
(1). 编写带有native方法的java类
(2). 使用javac命令编译所编写的java类
(3). 使用javah命令处理类文件,生成C/C++头文件
(4). 使用C/C++实现本地方法
(5). 将C/C++编写的文件生成动态连接库
个人觉得以上开发步骤中(4)(5)属于比较重要的步骤,需要好好理解
三、示例
这里以linux下jni开发为例 进行说明
1.确保gcc编译器已安装
2.编写HelloJNI.java代码,用native声明需要用C实现的函数。
public class HelloJNI
{ static { System.loadLibrary("goodluck"); } public native static int get(); public static void main(String[] args) |
这里说明的地方有两点:
i static
{
System.loadLibrary("goodluck");
}
linux的库文件必须是以libxxx.so形式命名的,其中xxx即为这里的goodluck,所以最后生成的linux库文件名称为libgoodluck.so。(windows库文件后缀为.dll,命名形式为xxx.so,如果windows环境下生成的动态链接库位goodluck.dll
ii main方法中
HelloJNI test = new HelloJNI();
test实例生成过程按照System.loadLibrary("goodluck")加载动态链接库libgoodluck.so
2.在HelloJNI.java文件所在目录下编译.java文件。
javac HelloJNI.java
3.编译第三步中生成的.class文件,生成对应的.h头文件,本例中生成的头文件名为HelloJNI.h
javah HelloJNI
4.编写HelloJNI.c文件,实现引用第4步中生成的.h头文件,并实现其中声明的方法。
[代码]
#include "HelloJNI.h"
int i = 0;
JNIEXPORT jint JNICALL Java_HelloJNI_get(JNIEnv *env, jclass jc)
{
return i;
}
JNIEXPORT void JNICALL Java_HelloJNI_set(JNIEnv *env, jclass jc, jint j)
{
i = j;
}
5.将第4步中编写的HelloJNI.c文件,编译成动态链接库文件
gcc -fPIC -I/usr/lib/jvm/java-1.5.0-sun-1.5.0.19/include -I/usr/lib/jvm/java-1.5.0-sun-1.5.0.19/include/linux -shared -o libgoodluck.so HelloJNI.c
注:/usr/lib/jvm/java-1.5.0-sun-1.5.0.19/include 是jni.h头文件所在的路径
/usr/lib/jvm/java-1.5.0-sun-1.5.0.19/include/linux 是jni_md.h所在的路径
-Idir 表示在你是用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如果没有找到,他回到缺省的头文件目录找,如果使用-I制定了目录,他回先在你所制定的目录查找,然后再按常规的顺序去找.
如果用到其他的非标准库 还需要添加-l参数,比如用到curses库,需要添加-lcurses