JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。 JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。
- 运行环境
CPU : AMD Moblie Athlon 64 3200+
Mem : 1024 MBOS : Windows xp sp2
JDK : java version "1.5.0_06"
IDE : Eclipse 3.1.2 、 Microsoft Visual Studio 2005 - 编写JAVA 代码
//JNITest.java
/**
* @author chunyv
*
*/
public class JNITest {/**
* @param args
*/
static
{
try
{
System.loadLibrary("JNITest");
}
catch(Exception e)
{
System.out.println("load library failure!");
}
}
public native static void version();
public native static void setint(int i);
public native static int getint();
public native static void setstr(String str);
public native static String getstr();
public native static void setgbk(byte[] gbkstr);
public native static byte[] getgbk();
public static void main(String[] args) {
// TODO Auto-generated method stub
String test = "Hello World!";
String test2 = "你好!\n\t\t--chunyv";
System.out.println("Proc Start");
byte[] end = {0};try
{
byte[] mybytedb = test2.getBytes("gbk");
byte[] mybyte = new byte[mybytedb.length + end.length];
System.arraycopy(mybytedb , 0 , mybyte , 0 ,mybytedb.length);
System.arraycopy(end , 0 , mybyte , mybytedb.length , end.length);
JNITest jnitest = new JNITest();
jnitest.setint(6);
System.out.println("setint ok");
System.out.println("get int form library :"+jnitest.getint());
System.out.println("getint ok");
jnitest.setstr(test);
System.out.println("setstr ok");
System.out.println(jnitest.getstr());
System.out.println("getstr ok");
jnitest.setgbk(mybyte);
System.out.println("setgbk ok");
System.out.println(jnitest.getgbk());
System.out.println("getgbk ok");
jnitest.version();
}
catch(Exception e)
{
e.printStackTrace();
}
}}
- 生成 .h 文件
javac JNITest.java
javah JNITest - 实现 JNITest.h 中的方法
/*
* author chunyv
* JNITest dll
*/#include "JNITest.h"
#include <windows.h>
JNIEXPORT void JNICALL Java_JNITest_version
(JNIEnv *, jclass)
{
printf("JNI Test\n\t\t--chunyv");
}
JNIEXPORT void JNICALL Java_JNITest_setint
(JNIEnv *, jclass, jint ii)
{
i = ii;
}
JNIEXPORT jint JNICALL Java_JNITest_getint
(JNIEnv *, jclass)
{
return i;
}
JNIEXPORT void JNICALL Java_JNITest_setstr
(JNIEnv * env, jclass, jstring jstr)
{
jboolean test = true;memset(str , 0 , sizeof(str));
sprintf_s(str ,env->GetStringUTFChars(jstr,&test));
env->ReleaseStringUTFChars(jstr , NULL);
}JNIEXPORT jstring JNICALL Java_JNITest_getstr
(JNIEnv * env, jclass)
{
return WindowsTojstring(env , str);
}JNIEXPORT void JNICALL Java_JNITest_setgbk
(JNIEnv * env, jclass, jbyteArray myjbyte)
{
memset(strgbk , 0 , sizeof(strgbk));sprintf_s(strgbk ,(char *)env->GetByteArrayElements(myjbyte,0));
}JNIEXPORT jstring JNICALL Java_JNITest_getgbk
(JNIEnv * env, jclass)
{
return WindowsTojstring(env , strgbk);
}jstring WindowsTojstring( JNIEnv* env, char* str_tmp )
{
jstring rtn = 0;
int slen = (int)strlen(str_tmp);
unsigned short * buffer = 0;
if( slen == 0 )
{
rtn = env->NewStringUTF(str_tmp );
}
else
{
int length = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str_tmp, slen, NULL, 0 );buffer = (unsigned short *)malloc( length*2 + 1 );
if( MultiByteToWideChar( CP_ACP, 0, (LPCSTR)str_tmp, slen, (LPWSTR)buffer, length ) >0 )
{
rtn = env->NewString( (jchar*)buffer, length );
}
}if( buffer )
{
free( buffer );
}return rtn;
} - 将生成的JNITest.dll 放到 .class 所在的目录 测试
java JNITestProc Start
setint ok
get int form library :6
getint ok
setstr ok
Hello World!
getstr ok
setgbk ok
你好!
--chunyv
getgbk ok
JNI Test
--chunyv
JNI 在 FreeBSD 上的应用
- 运行环境
CPU : Intel(R) Pentium(R) 4 CPU 2.40GHz (2393.94-MHz 686-class CPU)
Mem : 512 MB
OS : FreeBSD 6.2-PRERELEASE
JDK : java version "1.5.0"
IDE : vim + gcc 3.4.4 - java代码同上
- 生成 .h 文件同上
- 实现 JNITest.h 中的方法
/*
* author chunyv
* JNITest so
* add "int FreeBSD2Jstring(char * src ,
* char * dst,
* int * len);" into JNITest.h
*/#include <stdio.h>
#include <iconv.h>
#include <stdlib.h>
#include <string.h>
#include "JNITest.h"int i = 0;
char str[1024];
char strgbk[1024];JNIEXPORT void JNICALL Java_JNITest_version
(JNIEnv *env, jclass jc)
{
printf("JNI Test\n\t\t--chunyv\n");
}
JNIEXPORT void JNICALL Java_JNITest_setint
(JNIEnv * env, jclass jc, jint ii)
{
i = ii;
}
JNIEXPORT jint JNICALL Java_JNITest_getint
(JNIEnv * env, jclass jc)
{
return i;
}
JNIEXPORT void JNICALL Java_JNITest_setstr
(JNIEnv * env, jclass jc, jstring jstr)
{
jboolean test = 1;memset(str , 0 , sizeof(str));
sprintf(str ,(*env)->GetStringUTFChars(env ,jstr,&test));
(*env)->ReleaseStringUTFChars(env ,jstr , NULL);
}JNIEXPORT jstring JNICALL Java_JNITest_getstr
(JNIEnv * env, jclass jc)
{
return (*env)->NewStringUTF(env ,str);
}JNIEXPORT void JNICALL Java_JNITest_setgbk
(JNIEnv * env, jclass jc, jbyteArray myjbyte)
{
memset(strgbk , 0 , sizeof(strgbk));sprintf(strgbk ,(char *)(*env)->GetByteArrayElements(env ,myjbyte,0));
}JNIEXPORT jstring JNICALL Java_JNITest_getgbk
(JNIEnv * env, jclass jc)
{
char test[1024] ;
sprintf(test ,strgbk);
int len = (int ) strlen(strgbk);
if( FreeBSD2Jstring(test , strgbk ,&len ))
{
printf("convert error\n");
return NULL;
}
return (*env)->NewStringUTF(env ,strgbk);
}int FreeBSD2Jstring(char * src ,
char * dst,
int * len)
{
size_t n_in = strlen(src);
size_t n_out = *len+2;
memset(dst , 0 , n_out);
iconv_t test = iconv_open("UTF-8","GBK");
if(test == (iconv_t)-1)
{
printf("iconv open error\n");
return -1;
}
if((size_t)-1 == iconv(test ,(const char **) & src ,&n_in , & dst , &n_out))
{
printf("iconv convert error\n");
return -1;
}
if(test)
{
iconv_close(test);
}*len = n_out;
return 0;
} - 编译 .c 文件,将生成的库文件放到.class 所在目录并测试 .class
编译库文件
gcc -Wall -fPIC -shared -o libJNITest.so -I /usr/local/diablo-jdk1.5.0/include/ -I /usr/local/diablo-jdk1.5.0/include/freebsd/ -I /usr/local/include/ -liconv -L /usr/local/lib/ JNITest.c
测试 .class
java -Djava.library.path=./ JNITest - 测试结果
Proc Start
setint ok
get int form library :6
getint ok
setstr ok
Hello World!
getstr ok
setgbk ok
你好!
--chunyv
getgbk ok
JNI Test
--chunyv
JNI在Linux上的使用请参阅 《JNI在FreeBSD上的使用》部分
注:实例仅供参考,转载请注明出处,欢迎交流学习,谢谢!!