JNI全称是Java Native Interface(Java本地接口)单词首字母的缩写,本地接口就是指用C和C++开发的接口。由于JNI是JVM规范中的一部份,因此可以将我们写的JNI程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/C++写的大量代码。
开发JNI程序会受到系统环境的限制,因为用C/C++语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,而且各个平台对标准C/C++的规范和标准库函数实现方式也有所区别。这就造成使用了JNI接口的JAVA程序,不再像以前那样自由的跨平台。如果要实现跨平台,就必须将本地代码在不同的操作系统平台下编译出相应的动态库。
JNI开发流程主要分为以下6步:
1、编写声明了native方法的Java类
2、将Java源代码编译成class字节码文件
3、用javah -jni命令生成.h头文件(javah是jdk自带的一个命令,-jni参数表示将class中用native声明的函数生成jni规则的函数)
4、用本地代码实现.h头文件中的函数
5、将本地代码编译成动态库(windows:*.dll,linux/unix:*.so,mac os x:*.jnilib)
6、拷贝动态库至 java.library.path 本地库搜索目录下,并运行Java程序
通过上面的介绍,相信大家对JNI及开发流程有了一个整体的认识,下面通过一个HelloWorld的示例,再深入了解JNI开发的各个环节及注意事项。
PS:本人的开发环境为Mac os x 10.10.1 ,Eclipse 3.8(Juno),如果在其它操作系统下开发也是一样,只需将本地代码编译成当前操作系统所支持的动态库即可。
这个案例用命令行的方式介绍开发流程,这样大家对JNI开发流程的印象会更加深刻,后面的案例都采用eclipse+cdt来开发。
第一步、并新建一个HelloWorld.java源文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package com.study.jnilearn; public class HelloWorld { public static native String sayHello(String name); // 1.声明这是一个native函数,由本地代码实现 public static void main(String[] args) { String text = sayHello("yangxin"); // 3.调用本地函数 System.out.println(text); } static { System.loadLibrary("HelloWorld"); // 2.加载实现了native函数的动态库,只需要写动态库的名字 } } |
第二步、用javac命令将.java源文件编译成.class字节码文件
注意:HelloWorld放在com.study.jnilearn包下面
1 |
javac src/com/study/jnilearn/HelloWorld.java -d ./bin |
-d 表示将编译后的class文件放到指定的目录下,这里我把它放到和src同级的bin目录下
第三步、用javah -jni命令,根据class字节码文件生成.h头文件(-jni参数是可选的)
1 |
javah -jni -classpath ./bin -d ./jni com.study.jnilearn.HelloWorld |
默认生成的.h头文件名为:com_study_jnilearn_HelloWorld.h(包名+类名.h),也可以通过-o参数指定生成头文件名称:
1 |
javah -jni -classpath ./bin -o HelloWorld.h com.study.jnilearn.HelloWorld |
参数说明:
-classpath :类搜索路径,这里表示从当前的bin目录下查找
-d :将生成的头文件放到当前的jni目录下
-o : 指定生成的头文件名称,默认以类全路径名生成(包名+类名.h)
注意:-d和-o只能使用其中一个参数。
第四步、用本地代码实现.h头文件中的函数
com_study_jnilearn_HelloWorld.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_study_jnilearn_HelloWorld */ #ifndef _Included_com_study_jnilearn_HelloWorld #define _Included_com_study_jnilearn_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: com_study_jnilearn_HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_study_jnilearn_HelloWorld_sayHello (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif |
HelloWorld.c:
1 2 3 ass="crayon-nums " data-settings="show">
1 2 3 。
开发JNI程序会受到系统环境的限制,因为用C/C++语言写出来的代码或模块,编译过程当中要依赖当前操作系统环境所提供的一些库函数,并和本地库链接在一起。而且编译后生成的二进制代码只能在本地操作系统环境下运行,因为不同的操作系统环境,有自己的本地库和CPU指令集,而且各个平台对标准C/C++的规范和标准库函数实现方式也有所区别。这就造成使用了JNI接口的JAVA程序,不再像以前那样自由的跨平台。如果要实现跨平台,就必须将本地代码在不同的操作系统平台下编译出相应的动态库。 JNI开发流程主要分为以下6步: 1、编写声明了native方法的Java类 2、将Java源代码编译成class字节码文件 3、用javah -jni命令生成.h头文件(javah是jdk自带的一个命令,-jni参数表示将class中用native声明的函数生成jni规则的函数) 4、用本地代码实现.h头文件中的函数 5、将本地代码编译成动态库(windows:*.dll,linux/unix:*.so,mac os x:*.jnilib) 6、拷贝动态库至 java.library.path 本地库搜索目录下,并运行Java程序 通过上面的介绍,相信大家对JNI及开发流程有了一个整体的认识,下面通过一个HelloWorld的示例,再深入了解JNI开发的各个环节及注意事项。 PS:本人的开发环境为Mac os x 10.10.1 ,Eclipse 3.8(Juno),如果在其它操作系统下开发也是一样,只需将本地代码编译成当前操作系统所支持的动态库即可。 这个案例用命令行的方式介绍开发流程,这样大家对JNI开发流程的印象会更加深刻,后面的案例都采用eclipse+cdt来开发。 第一步、并新建一个HelloWorld.java源文件
第二步、用javac命令将.java源文件编译成.class字节码文件 注意:HelloWorld放在com.study.jnilearn包下面
-d 表示将编译后的class文件放到指定的目录下,这里我把它放到和src同级的bin目录下 第三步、用javah -jni命令,根据class字节码文件生成.h头文件(-jni参数是可选的)
默认生成的.h头文件名为:com_study_jnilearn_HelloWorld.h(包名+类名.h),也可以通过-o参数指定生成头文件名称:
参数说明: -classpath :类搜索路径,这里表示从当前的bin目录下查找 -d :将生成的头文件放到当前的jni目录下 -o : 指定生成的头文件名称,默认以类全路径名生成(包名+类名.h) 注意:-d和-o只能使用其中一个参数。 第四步、用本地代码实现.h头文件中的函数 com_study_jnilearn_HelloWorld.h:
HelloWorld.c: |