浅试 JNI编程

好吧,开始我的第一个JNI试验小程序

HelloWorld.java 代码清单

 1 public class HelloWorld {
 2 
 3     static {
 4         System.loadLibrary("HelloWorld");
 5     }
 6 
 7     public static native void hello(String msg);
 8 
 9 
10     public static void main(String args[]){
11         HelloWorld hw = new HelloWorld();
12         hw.Display();
13     }
14 
15     void Display(){
16         System.out.println("hello,world");
17     }
18 
19 }

 记得文件名必须和类名一致,编译

  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设置为当前目录。

posted @ 2015-09-03 15:37  zengsiyu  阅读(178)  评论(0编辑  收藏  举报