好吧,开始我的第一个JNI试验小程序
HelloWorld.java 代码清单
public class HelloWorld { static {
System.loadLibrary("HelloWorld");
} public static native void hello(String msg); public static void main(String args[]){
HelloWorld hw = new HelloWorld();
hw.Display();
} void Display(){
System.out.println("hello,world");
} }
记得文件名必须和类名一致,编译
javac HelloWorld
利用 javah 命令生成c 的头文件,命令形式 javah <packagename>.<classname>,因为我没有定义包名,所以直接是类名:
javah HelloWorld
这样在目录下将会生成以包名为文件名的头文件 HelloWorld.h
/* 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: hello
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_HelloWorld_hello
(JNIEnv *, jclass, jstring); #ifdef __cplusplus
}
#endif
#endif
下面我们需要建立HeloWorld的动态共享库,先创建一个HelloWorld.c, 然后将头文件中的函数定义拷贝过来,并且指定参数的变量名
#include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_hello(JNIEnv * env, jclass jz, jstring s)
{
}
这是个毫无用处的函数,在java程序中我们也只有声明,没有调用,现在我只是试验他是否能正常装载。用 gcc 命令进行编译:
gcc -I/usr/lib/jdk1.6.0_45/include -I/usr/lib/jdk1.6.0_45/include/linux -fPIC -c HelloWorld.c
gcc的 -I 选项指定头文件的搜索路径,jni.h 在jdk 的include子目录里,而jni_md.h在 include/linux下,所以要把这两个路径加入头文件的搜索路径。-c 选项指定生成 .o 文件,如果缺少 -c 选项gcc会自动链接生成可执行文件,因为在我们的程序中缺少 main 函数,所以会出现错误。另外我们希望生成的是动态链接库,所以我们不需要生成可执行文件,只要生成目标文件即可。经过执行上面的命令,在目录下会生成 HelloWorld.o
我们执行下面的命令生成动态链接库
gcc -shared -o libHelloWorld.so HelloWorld.o
-shared 指示生成共享库, 而 -o 可以指定生成的共享库的文件名,注意linux下共享库的命名是有讲究的,首先文件名必须由lib作为前缀,其次扩展名为.so, 而他们之间的名字应该和 System.loadLibrary调用指定的名字相符,而且大小写一致。
回头看看我们java文件中的代码片段:
public class HelloWorld { static {
System.loadLibrary("HelloWorld"); // 会寻找 libHelloWorld.so 动态库
} ... }
下一步使用java 命令运行我们的java程序:
java HelloWorld
会报告错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1738)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1028)
at HelloWorld.<clinit>(HelloWorld.java:6)
Could not find the main class: HelloWorld. Program will exit.
这是因为java找不到我们的动态库。我们很奇怪的是明明动态库就在当前的目录下,而且文件的命名也符合标准,为何还找不到。这里的原因是java程序并非足够的智能,根据错误的提示可以知道我们可以通过设置 java.library.path 变量来指定库的搜索路径,好这样一来,问题就简单了,运行下面的命令,搞定:
java -Djava.library.path=. HelloWorld
通过将java.libray.path=. 来将java.libray.path设置为当前目录。