注:此过程在mac环境下
JNI开发流程简介
- 编写声明了 native 方法的 Java 类
- 将 Java 源代码编译成 class 字节码文件
- 用 javah -jni 命令生成
.h
头文件(javah 是 jdk 自带的一个命令,-jni 参数表示将 class 中用native 声明的函数生成 JNI 规则的函数)
- 用本地代码实现
.h头
文件中的函数
- 将本地代码编译成动态库(Windows:*.dll,linux/unix:*.so,mac os x:*.jnilib)
- 拷贝动态库至 java.library.path 本地库搜索目录下,并运行 Java 程序
尝试JNI
一.定义一个native 函数
HelloWorld.java
1 2 3 4 5 6 7 8 9 10 11 12
| public class HelloWorld { static { } public static native String sayHello(String name); public static void main(String... args) { String text = sayHello("zpauly"); System.out.println(text); } }
|
二.使用将.java文件编译为.class文件
1
| javac src/HelloWorld.java -d bin
|
这里我使用-d命令将class文件生成到指定目录下
三.根据.class文件生成.h头文件
1
| javah -jni -classpath bin -d jni HelloWorld
|
默认生成的头文件的名称为:包名+类名.h,如:若此处HelloWorld的包名为1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| javah -jni命令参数 - classpath:类搜索路径,这里表示从当前的 bin 目录下查找 - d:将生成的头文件放到当前的 jni 目录下 - o: 指定生成的头文件名称,默认以类全路径名生成(包名+类名.h) 此时生成的头文件为 > HelloWorld.h ```c++ /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif
|
四.实现头文件中的函数
HelloWorld.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include "HelloWorld.h" #ifdef __cplusplus extern "C" { #endif * Class: HelloWorld * Method: sayHello * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello(JNIEnv *env, jclass clazz, jstring j_str) { const char *c_str = NULL; char buff[128] = { 0 }; c_str = (*env)->GetStringUTFChars(env, j_str, NULL); if (c_str == NULL) { printf("out of memory.\n"); return NULL; } (*env)->ReleaseStringUTFChars(env, j_str, c_str); printf("Java String:%s\n", c_str); sprintf(buff, "hello %s\n", c_str); return (*env)->NewStringUTF(env, buff); } #ifdef __cplusplus } #endif
|
五.将写好的c/c++代码编译为本地动态库
动态库命名规则:lib+动态库文件名+后缀
1
| gcc -dynamiclib -o jni/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/include/darwin
|
参数说明:
- -dynamiclib:表示编译成动态链接库
- -o:指定动态链接库编译后生成的路径及文件名
- -framework JavaVM -I:编译 JNI 需要用到 JVM 的头文件(
jni.h
),第一个目录是平台无关的,第二个目录是与操作系统平台相关的头文件
六.运行Java程序
运行效果