ZhangLiHai.Com

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/