java里的jni是用于java源码里调用c/c++实现的动态库.
实现步骤:
1 先用eclipse创建一个java工程,新建一个类:
/* Hello.java */
package com.jk;
public class Hello {
public native void sayhello(String str); //在c/c++库里实现的函数加上native声明, 这个函数成员在这里只要声明,函数体由c/c++实现.
}
2 写好上面类的代码后, 编译工程(会报没有main函数,没有影响).
接着进入工程源码里生成的bin目录下打开终端里, 使用javah产生头文件
javah -jni com.jk.Hello //它会产生com_jk_Hello.h的头文件, 头文件里已声明我们要实现函数
/* com_jk_Hello.h */
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jk_Hello */
#ifndef _Included_com_jk_Hello
#define _Included_com_jk_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jk_Hello
* Method: sayhello
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_jk_Hello_sayhello
(JNIEnv *, jobject, jstring); // jstring才是参数,前面两个参数是固定的
#ifdef __cplusplus
}
#endif
#endif
3 用一个c源文件实现头文件里声明的函数体.
/* com_jk_Hello.c */
#include <stdio.h>
#include "com_jk_Hello.h"
JNIEXPORT void JNICALL Java_com_jk_Hello_sayhello
(JNIEnv *env, jobject obj, jstring str)
{
//把jstring参数转换成c语言里的char *
const char *data = (*env)->GetStringUTFChars(env, str, 0);
printf("in jni: %s\n", data);
}
编译成动态库libHello.so时需要指定jdk里的头文件所在路径 :
gcc -shared -fPIC -o libHello.so -I /usr/lib/jvm/java-1.8.0-openjdk/include/ -I /usr/lib/jvm/java-1.8.0-openjdk/include/linux/ com_jk_Hello.c
4 在eclipse里新建一个java工程,在工程里调用动态库libHello.o
/* Hello.java */
package com.jk;
public class Hello {
public native void sayhello(String str);
static {
System.loadLibrary("Hello"); //注意"Hello"就是表示libHello.so
}
public static void main(String args[]) {
Hello m = new Hello();
m.sayhello("what");
}
}
注意包名,类名必须与步骤1时的一致
5 编译时需要指定libHello.so动态库的路径,否则会报库在java.libary.path里找不到的错误.
指定库的路径: 打开工程属性–> java build path –> libary(库) –> native libary path(本机库位置) –> 用右边的编辑按钮,选中库所在路径.
jni里代码在c里使用JNIEnv *env, 需要(*env)->GetStringUTFChars(env, str, 0);
在c++里, env->GetStringUTFChars(str, 0);
把jstring转成char *
c语言: char *data = (*env)->GetStringUTFChars(env, str, 0);
c++: char *data = env->GetStringUTFChars(str, 0);
jint可以直接作int变量来使用
把jbyteArray arr转成char数组来用:
c++: char *data = env->GetByteArrayElements(arr, 0);
int len = env->GetArrayLength(arr, 0);
如果需要把传过来的jbyteArray arr数组,改变里面的数据并返回:
char *data = (char *)env->GetByteArrayElements(arr, 0);
int len = env->GetArrayLength(arr);
//改变arr数组里数据后,设置返回
env->SetByteArrayRegion(arr, 0, len, (jbyte *)data);