我们知道java是可以调用C/C++程序的,也就时JNI编程,我们以一个最简单的Helleworld!程序,下面的程序实在Ubuntu11.04上面实现的。
首先,定义java类,在java类中声明native方法,如下:
1 public class Main { 2 3 static { 4 System.loadLibrary("main"); 5 } 6 7 private native void jniTest(String str); 8 9 /** 10 * @param args 11 */ 12 public static void main(String[] args) { 13 Main main = new Main(); 14 String str = "hello world!"; 15 main.jniTest(str); 16 } 17 18 }
代码中有System.loadLibrary("main");也就是加载共享库,这个库是什么来头后面会说到。
然后,通过javac编译java源文件,得到对应的class文件,这个大家都知道的。
之后,通过javah生成头文件,在我们的例子中就是:javah Main ,我们会得到如下头文件:
1 /* DO NOT EDIT THIS FILE - it is machine generated */ 2 #include <jni.h> 3 /* Header for class Main */ 4 5 #ifndef _Included_Main 6 #define _Included_Main 7 #ifdef __cplusplus 8 extern "C" { 9 #endif 10 /* 11 * Class: Main 12 * Method: jniTest 13 * Signature: (Ljava/lang/String;)V 14 */ 15 JNIEXPORT void JNICALL Java_Main_jniTest 16 (JNIEnv *, jobject, jstring); 17 18 #ifdef __cplusplus 19 } 20 #endif 21 #endif
然后,根据头文件编写对应函数的实现,即对应的.c文件,也就是实现Java_Main_jniTest()函数,如下所示:
1 #include "Main.h" 2 #include <stdio.h> 3 4 JNIEXPORT void JNICALL Java_Main_jniTest(JNIEnv *evn, jobject obj, jstring jstr) 5 { 6 const jbyte* str =(const jbyte*) (*evn)->GetStringUTFChars(evn, jstr, JNI_FALSE); 7 printf("%s\n", str); 8 (*evn)->ReleaseStringUTFChars(evn, jstr, (const char* )str); 9 return; 10 }
接下来根据.c文件编译生成动态共享库,即.so文件。在这儿生成共享库时使用GCC, 必须通知编译器在何处查找此 Java 本地方法的支持文件(支持文件在不同的系统路徑有所不同),并且显式通知编译器生成位置无关的代码,如下所示
gcc -I/usr/lib/jvm/jdk1.6.0_32/include/ -I/usr/lib/jvm/jdk1.6.0_32/include/linux -fPIC -shared -o libmain.so Main.c
其中-fPIC是-f参数后面接一些编译选项,PIC是其中一种,表示生成位置无关代码(Position Independent Code),置无关码就是可以在进程的任意内存位置执行的目标码,动态链接库必须使用。其次,Linux规定库的命名必须是:lib+库名+.so,链接的时候只需提供库名就可以了。
生成的动态共享库还需要告诉动态链接程序此共享文件的路径,也就时系统环境变量:LD_LIBRARY_PATH,一般可以这样设定
export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH
到这儿就算大功告成,在命令行执行Main.class就行了:java Main