『阿男的技术分享』*Java Native Interface(下)*
接下来我们写一个HelloJNI.c
来实现这个HelloJNI.h
:
#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
这个代码就非常简单,就是实现了Java_HelloJNI_sayHello
,功能就是printf("Hello World!\n");
。我们编译这个代码:
$ c++ -c -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" HelloJNI.c
注意阿男实在MacOS上编译,所以引用的是MacOS的JDK的include
目录,此外MacOS的内核名叫darwin
,你如果用Linux系统,你的JDK的include
目录里应该有一个linux
目录,对应上面的darwin
目录。
这两个-I
主要是为了引用JNI
相关的库文件:
$ ls $JAVA_HOME/include/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/jni.h
$ ls $JAVA_HOME/include/darwin/jni*
/Library/Java/JavaVirtualMachines/jdk1.8.0_66.jdk/Contents/Home/include/darwin/jni_md.h
这两个.h
文件是必须的。编译完成后,我们就得到了object文件:
$ ls *.o
HelloJNI.o
用nm
命令看一下这个object file里面的符号:
$ nm HelloJNI.o
0000000000000000 T _Java_HelloJNI_sayHello
U _printf
可以看到包含的的methods。我们要把这个object文件链接成library,在MacOS下命令如下:
$ c++ -dynamiclib -o libhello.jnilib HelloJNI.o
这样我们就得到了Java可以调用的libhello.jnilib
:
$ ls *.jnilib
libhello.jnilib
我们在Java代码里写的是System.loadLibrary("hello")
,但是这里的library名字叫做libhello
,前面多了lib
,这是一种命名约定。
如果你在Linux系统下,生成library的命令不太一样,需要用下面的命令生成.so
文件,也就是shared library文件:
cc -shared -fpic -o libhello.so -I/usr/java/include -I/usr/java/include/linux HelloJNI.c
接下来就是编译Java代码:
$ javac HelloJNI.java
我们得到class文件:
$ ls *.class
HelloJNI.class
此时目录里应该有我们的library还有class文件:
$ ls *.class *.jnilib
HelloJNI.class libhello.jnilib
此时我们可以使用java
命令运行HelloJNI.class
:
$ java HelloJNI
Hello World!
可以看到我们这个Hello World!
字符串是来自于native method的Java_HelloJNI_sayHello
里面的printf
。我们的Java代码与原生平台进行了交互。
参考资料: