首先在主目录下创建需要的文件夹。java目录存放java源码及编译文件、cpp目录存放cpp源码及编译文件。
在java目录下创建名为Hello.java的文件,内容如下:
public class Hello { public native String sayHello(); static { System.loadLibrary("Hello"); } }编译,并生成本地链接库至cpp目录
javac -classpath java/ java/Hello.java javah -d cpp/ -classpath java/ Hello
在cpp目录下创建名为Hello.cpp的文件,内容如下:
#include "Hello.h" JNIEXPORT jstring JNICALL Java_Hello_sayHello(JNIEnv *env, jobject obj) { return env->NewStringUTF("Hello world"); }在生成共享库之前,需要将JDK下两个头文件软链接至/usr/include/,如下图:
cd /usr/include/ sudo ln -s ~/local/jdk1.6.0_37/include/jni.h sudo ln -s ~/local/jdk1.6.0_37/include/linux/jni_md.h ls -l | grep 'jni'
当然,这一步是非必需的。
编译生成共享库。如果没有做上一步,则执行以下两条命令。
g++ -I/home/insongr/local/jdk1.6.0_37/include -I/home/insongr/local/jdk1.6.0_37/include/linux -fPIC -c Hello.cpp g++ -shared -Wl,-soname,libHello.so.l -o libHello.so.1.0 Hello.o否则,执行下面的命令即可。
g++ -fPIC -c Hello.cpp g++ -shared -Wl,-soname,libHello.so.l -o libHello.so.1.0 Hello.o拷贝生成的共享库为标准文件名:
最后,在java目录中创建测试类HelloJni.java,内容如下:
public class HelloJni { public static void main (String args[]) { Hello hello = new Hello(); System.out.println(hello.sayHello()); } }编译并运行:
javac HelloJni.java java -Djava.library.path=/home/insongr/jni/cpp HelloJni
如果不想在命令行中加-D参数,而是在代码中动态更改java.library.path,则代码如下:
import java.lang.reflect.Field; public class HelloJni { public static void main (String args[]) { try { System.setProperty("java.library.path", "../cpp"); Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); fieldSysPath.setAccessible(true); fieldSysPath.set(null, null); Hello hello = new Hello(); System.out.println(hello.sayHello()); } catch(Exception e) { e.printStackTrace(); } } }编译并运行:
如果仅仅增加代码:
System.setProperty("java.library.path", "../cpp");是没有作用的,因为java.library.path的值在第一次加载时就已经缓存了。可以通过反射机制将ClassLoader的sys_paths变量置为null,达到重新读取java.library.path的目的。