注意:System.loadLibrary函数的参数是动态库名,而不是动态库的函数名
package ttt;
import java.io.*;
public class test
{
static
{
System.loadLibrary("test"); //对应libtest.so,注意这里不能使用libtest.so,只需要写lib跟.so之间的内容
}
public static native byte[] getAll(); //jni对外提供的调用接口
public static native byte[] getSingle(int i);
public static void main(String[] args) {
System.out.println(new String(getAll()));
System.out.println(new String(getSingle(2)));
}
}
因为test.java代码放在ttt目录下,到ttt目录外,执行javah ttt/test或javah -classpath . ttt,以便生成.h,这里生成的.h文件名为jni_ttt.h,该文件的内容为:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class jni_test */ #ifndef _Included_jni_test #define _Included_jni_test #ifdef __cplusplus extern "C" { #endif /* * Class: jni_test * Method: getAll * Signature: ()[B */ JNIEXPORT jbyteArray JNICALL Java_jni_test_getAll (JNIEnv *, jclass); /* * Class: jni_test * Method: getSingle * Signature: (I)[B */ JNIEXPORT jbyteArray JNICALL Java_jni_test_getSingle (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif其中,Java_jni_test_getAll、Java_jni_test_getSingle为接口函数,注意其返回值为jbyteArray。利用这个.h文件,编写一个.c或.cpp文件,实现相应的接口函数
注意,接口函数的参数都包含一个JNIEnv的上下文指针,通过这个上下文指针,可以调用jni库中的函数进行操作,
比如将char* 转换为 jbyteArray的代码如下:
JNIEXPORT jbyteArray JNICALL Java_jni_test_getSing(JNIEnv *env, jclass jc, jint i)
{
....
char *strBuf = NULL; strBuf = malloc(100); strncpy(strBuf , input, 99); jbyteArray byteBuf = env->NewByteArray(strlen(strBuf )); //创建一个java的byte数组 env->SetByteArrayRegion(byteBuf , 0, strlen(strBuf), (jbyte*)strBuf ); if(strBuf) { free(strBuf); }
...
}
error: request for member NewByteArray in something not a structure or union
error: request for member SetByteArrayRegion in something not a structure or union
对c++来说就相对简单一些
编译这个c或cpp代码使用:
gcc -fPIC -D_REENTRANT -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/ -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/linux -c jni_test.c (使用c方式)
g++ -fPIC -D_REENTRANT -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/ -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/linux -c jni_test.c (使用c++方式)
其中:
(/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/和/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/linux 为c、c++程序要用到的jni.h头文件所在的路径)
g++ -shared -Wl,-soname,libtest.so.1 -o libtest.so jni_test.o
生成libtest.so
Exception in thread "main" java.lang.NoClassDefFoundError: ttt/test
Caused by: java.lang.ClassNotFoundException: ttt.test.class
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
原因是classpath没有当前路径。改正后执行如下命令:
java -cp . ttt/test
jar -cef ttt.test test.jar ttt
c代表生成新的jar包;
e代表可执行的类,亦即main方法所在的类。书写时要加上包名,在本例中是后面的ttt.test;
f代表生成的jar包的名称,在本例中是test.jar。此包名可以随意命名,没有规定;
最后面的这个参数表示将ttt目录下的所有文件都打包放到新的jar包中。
参考:http://blog.csdn.net/xiaojianpitt/article/details/5652223