About JNI...
2006-8-29 11:37:17
其实JNI的应用说起来很简单。 网上的例子也很多,但是网上的例子大都是互相抄袭,没有人详细说明,大部分例子都是错误的。JNI,应用起来很简单,以下例子是在Linux下测试:
一个Java类文件,如果部分方法需要本地程序实现那么可以简单声明如下: public static native void test();
只是声明这样一个空方法,不需要实现,然后在静态装在块写入如下: static{ System.loadLibrary(yourLibName); }
测试代码如下:
假如我们有一个方法需要记录一下日志。其中写文件部分用本地方法实现:
TestLog.java 代码如下:
public class TestLog{ static{ System.loadLibrary("clog"); } public static native void log(String str); public static void main(String[] args){ log("Hello,Goold"); } }//~ TestLog.java End 假如你的系统CLASSPATH,PATH都有配置java环境变量
$>javac TestLog.java $>javah TestLog 执行javah命令行后会生成一个TestLog.h的c头文件,本例中的代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class TestLog */ #ifndef _Included_TestLog #define _Included_TestLog #ifdef __cplusplus extern "C" { #endif /* * Class: TestLog * Method: log * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_TestLog_log (JNIEnv *, jclass, jstring); #ifdef __cplusplus } #endif #endif
//~ TestLog.h End
接下来就是实现TestLog.h里面的方法,建立一个TestLog.c文件,代码如下:
#include <stdio.h> #include <time.h> #include <TestLog.h> JNIEXPORT void JNICALL Java_TestLog_log (JNIEnv *env, jclass jobj, jstring jstr){ FILE *fp = fopen("nlog.log","a+"); if(fp) { const char *str =(*env)->GetStringUTFChars(env, jstr, NULL); time_t now=time(0); struct tm *now_tm = localtime(&now); char date[80]; strftime(date,sizeof(date),"%D %H:%M:%S",now_tm); fprintf(fp,"[%s] ",date); fprintf(fp,str); fclose(fp); (*env)->ReleaseStringUTFChars(env, jstr, str);//此处要通知jvm进行回收 } } //~TestLog.c End
接下来就是调用cc命令进行编译,连接。 命令如下:
其中$JAVA_HOME替换成自己的目录,这里没有写Makefile文件 $>cc -c -g -fno-exceptions -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -I ./ TestLog.c -o TestLog.o
$>cc -g -fno-exceptions -fPIC -DPIC -shared TestLog.o -o libclog.so
到目前有两点要注意的:
1 关于本地库的方法名字,是程序中调用的名字前加上“lib” ,如本例中的 System.loadLibrary("clog"); 而我生成的文件确实libclog.so; 关于java.library.path,系统默认的java.library.path是$JAVA_HOME/jre/bin/i386/等目录。在执行java程序前可以把本地库cp到系统默认的path下,也可以在执行时候制定path,如:java -Djava.library.path=youLibPath TestLog
2 当执行程序遇到"ELF file's phentsize not the expected size"错误时候可能是你的本地库只编译了,而没有进行连接。
最后执行一下本例中的测试就可以了。
相关的参考文章:
http://www.iplab.cs.tsukuba.ac.jp/~liuxj/jdk1.2/zh/docs/guide/jni/spec/jniTOC.doc.html
http://ringlord.com/publications/jni-howto/
|