本文共 6280 字,大约阅读时间需要 20 分钟。
public class TestJni { static { //1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public static void main (String args[]) { // 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数 test_demo(); }}
在java中调用 c 语言中的 test_demo 函数,有两种方式
TestJni.java:7: error: missing method body, or declare abstract public static void test_demo(); ^1 error
public class TestJni { static { //1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public native static void test_demo(); public static void main (String args[]) { // 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数 test_demo(); }}
public class TestJni { static { //1. 使用静态代码块加载 c库 System.loadLibrary("testJni"); /* libtestJni.so */ } public native void test_demo(); public static void main (String args[]) { TestJni t = new TestJni(); // 2. java 源码中 映射到需要调用的 c函数 //调用相应的函数,如果加了static,直接使用test_demo()即可调用 t.test_demo(); }}
#inlcudevoid test_demo(){ printf("func:%s, line:%d\n", __func__, __LINE__);}int main() { return 0;}
那么怎么调用呢?
编译java代码的命令
javac -encoding gbk TestJni.java
javah -jni TestJni
会在目录下面生成一个TestJni.h
这里会写c语言中函数名称应该写成什么样,其实是 类名+函数名
sgy@ubuntu:~/sgy/java_learn/jni_learn$ cat TestJni.cat: TestJni.: No such file or directorysgy@ubuntu:~/sgy/java_learn/jni_learn$ cat TestJni.h/* DO NOT EDIT THIS FILE - it is machine generated */#include/* Header for class TestJni */#ifndef _Included_TestJni#define _Included_TestJni#ifdef __cplusplusextern "C" { #endif/* * Class: TestJni * Method: test_demo * Signature: ()V */JNIEXPORT void JNICALL Java_TestJni_test_1demo (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endifsgy@ubuntu:~/sgy/java_learn/jni_learn$
#include#include #include "TestJni.h"JNIEXPORT void JNICALLJava_TestJni_test_1demo(JNIEnv *env, jobject obj){ printf("func:%s, line:%d\n", __func__, __LINE__);return;}int main() { return 0;}
编译成动态库
gcc -fPIC -shared -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux/ -o libtestJni.so testJni.c
告诉java 动态库的路径,需要设置环境变量
export LD_LIBRARY_PATH=.
运行java的命令
java TestJni
第一种方法,c语言的函数的名字比较固定,第二种可以比较方便的指定对应关系
jni.pdf—>8.4.1 The JNI_OnLoad Handler
void test(){ printf("func:%s, line:%d\n", __func__, __LINE__);}static const JNINativeMethod methods[] = { { "test_demo", "()V", test}, };JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){ JNIEnv *env; jclass cls; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) { return JNI_ERR; /* JNI version not supported */ } cls = (*env)->FindClass(env, "TestJni"); if (cls == NULL) { return JNI_ERR; } if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) { return JNI_ERR; } return JNI_VERSION_1_4;}
- cls = (*env)->FindClass(env, “JNIDemo”); 先要找到对应的类,返回一个cls
- (*env)->RegisterNatives(env, cls, methods, 1) 注册对应java函数和c函数的对应关系,对应关系存在methods结构体里面
typedef struct { char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */} JNINativeMethod;static const JNINativeMethod methods[] = { { "test_demo", "()V", test}, };
最后的源代码
#include#include #include "TestJni.h"JNIEXPORT void JNICALLJava_TestJni_test_1demo(JNIEnv *env, jobject obj){ printf("func:%s, line:%d\n", __func__, __LINE__); return;}void test(){ printf("func:%s, line:%d\n", __func__, __LINE__);}static const JNINativeMethod methods[] = { { "test_demo", "()V", test}, };JNIEXPORT jint JNICALLJNI_OnLoad(JavaVM *jvm, void *reserved){ JNIEnv *env; jclass cls; if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) { return JNI_ERR; /* JNI version not supported */ } cls = (*env)->FindClass(env, "TestJni"); if (cls == NULL) { return JNI_ERR; } if ((*env)->RegisterNatives(env, cls, methods, 1) < 0) { return JNI_ERR; } return JNI_VERSION_1_4;}int main() { return 0;}
signature的格式和介绍
jni的字段描述符 对于参数是String类, signature应该写成 Ljava/lang/String; 对于其他类,统一写成 Ljava/lang/Object;TestJni.java 里面的函数改成下面这个样子
public native static int test_demo(int java_var); System.out.println(test_demo(1));
testJni.c
jint test(JNIEnv *env, jclass cls, jint java_var){ printf("func:%s, line:%d, java_var:%d\n", __func__, __LINE__, java_var); return 2;}
执行结果
func:test, line:13, java_var:12
jni.pdf—>P39
TestJni.java 里面的函数改成下面这个样子
public native static String test_demo(String java_str); System.out.println(test_demo("java_str"));
testJni.c
jstring test(JNIEnv *env, jclass cls, jstring java_str){ const jbyte *str; str = (*env)->GetStringUTFChars(env, java_str, NULL); if (str == NULL) { return NULL; /* OutOfMemoryError already thrown */ } printf("func:%s, line:%d, java_str:%s\n", __func__, __LINE__, str); return (*env)->NewStringUTF(env, "c_str");;}static const JNINativeMethod methods[] = { { "test_demo", "(Ljava/lang/String;)Ljava/lang/String;", test}, };
执行结果
func:test, line:20, java_str:java_strc_str
jni.pdf—>P49
TestJni.java 里面的函数改成下面这个样子
public native static int test_demo(int array[]); int array[] = { 1, 2, 3}; System.out.println(test_demo(array));
testJni.c
jint test(JNIEnv *env, jclass cls, jintArray java_array){ jint i = 0; jint sum = 0; jint *cArray; cArray = (*env)->GetIntArrayElements(env, java_array, NULL); if (cArray == NULL) { return 0; /* exception occurred */ } for (i = 0; i < (*env)->GetArrayLength(env, java_array); i++) { sum += cArray[i]; } (*env)->ReleaseIntArrayElements(env, java_array, cArray, 0); return sum;}static const JNINativeMethod methods[] = { { "test_demo", "([I)I", test}, };
执行结果
6
jni关于数组提供的一些函数接口
PS:疑问
Exception in thread "main" java.lang.NoSuchMethodError: Method TestJni.test_demo()V name or signature does not match
转载地址:http://ihyci.baihongyu.com/