JNI的全称是java native interface,用来调用某些特定于系统平台或者硬件的操作,但是它只能调用c/c++的代码,若是其它语言代码,只能通过c/c++进行二次调用。
关于JNI的完整技术文档,大家可以查看下面这个网址:
下面我们看下JNI如何执行回调函数:
我们知道在c/c++回调函数可以通过函数指针执行,但是在Java中已经没有指针的概念,在这里,我们先传递一个类对象给native函数,然后再dll中调用期望的函数即可。
下面的这个例子中,我们通过回调传递一个字符串给java,这在java和c/c++混合编程时传递dll内部的出错或其他信息到java层是很有用的。
1. 首先创建一个java类文件,封装一个native函数和一个用于回调的函数
package
jni;
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
public
class
Log
...
{
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
static...{
System.loadLibrary("mylib");
}
//用来回调,输出c代码层的信息
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public void output(String out)...{
System.out.println(out);
}
//native函数,用来传递对象
public native void test(Log log);
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
public static void main(String[] args)...{
Log log = new Log();
log.test(log);
}
}
2. 调用javah命令,生成对应的c/c++都文件
/**/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
<
jni.h
>
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
/**/
/* Header for class jni_Log */
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#ifndef _Included_jni_Log
#define _Included_jni_Log
#ifdef __cplusplus
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
extern
"
C
"
...
{
#endif
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
/**//*
* Class: jni_Log
* Method: test
* Signature: (Ljni/Log;)V
*/
JNIEXPORT void JNICALL Java_jni_Log_test
(JNIEnv *, jobject, jobject);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
#ifdef __cplusplus
}
#endif
#endif
3. 利用vc和生成的头文件完成一个dll
#include
<
windows.h
>
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
#include
"
jni_Log.h
"
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
int
WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReasion,PVOID pvReserved)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
return TRUE;
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
JNIEXPORT
void
JNICALL Java_jni_Log_test(JNIEnv
*
env, jobject obj, jobject log)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
jclass cls = (*env)->GetObjectClass(env, log);
jmethodID jmid = (*env)->GetMethodID(env, cls, "output", "(Ljava/lang/String;)V");
jstring info = (*env)->NewStringUTF(env, "i am a error!");
(*env)->CallVoidMethod(env,log, jmid,info);
(*env)->ReleaseStringUTFChars(env,info,(*env)->GetStringUTFChars(env, info, FALSE));
}
编译完成后,将mylib.dll放到与jni同级的目录中,运行命令java jni.Log,即可看到控制台成功打印信息
"i am a error!"。