首先了解下,什么是JNI, JNI是Java Native Interface的缩写。从Java 1.1开始,Java Native Interface (JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。
#include
<
objbase.h
>

#include
<
iostream.h
>

extern
"
C
"
__declspec(dllexport)
void
sayHello (
char
*
name)


...
{

cout<<"Hello "<<name<<endl;

}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason,
void
*
lpReserved)


...
{

HANDLE g_hModule;

switch(dwReason)


...{

case DLL_PROCESS_ATTACH:

g_hModule = (HINSTANCE)hModule;

break;

case DLL_PROCESS_DETACH:

g_hModule=NULL;

break;

}

return TRUE;

}
public
class
j_dll
...
{

public native void sayHello(String name);


public static void main(String[] args) ...{
// TODO Auto-generated method stub
}
}
javac j_dll.java
javah j_dll
/**/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
<
jni.h
>

/**/
/* Header for class j_dll */

#ifndef _Included_j_dll
#define
_Included_j_dll
#ifdef __cplusplus

extern
"
C
"
...
{
#endif

/**//*
* Class: j_dll
* Method: sayHello
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_j_1dll_sayHello
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif
这个文件是自动生成的,无需修改!这里的JNIEXPORT void JNICALL Java_j_1dll_sayHello
(JNIEnv *, jobject, jstring);方法就是按照java类中的sayHello方法生成的。
#include
"
stdio.h
"
#include
"
j_dll.h
"
#include
<
windows.h
>
#include
<
iostream.h
>


//
加载dll
HINSTANCE hinst
=
NULL;

JNIEXPORT
void
JNICALL Java_j_1dll_sayHello(JNIEnv
*
env, jobject obj, jstring s)

...
{
//定义一个函数指针
typedef void (* sayHello )(char * name);
//定义一个函数指针变量
sayHello sh = NULL;

if (NULL == hinst)

...{
hinst=::LoadLibrary("c_dll.dll");
}
//找到dll的sayHello函数
sh =(sayHello)GetProcAddress(hinst, "sayHello");
//调用dll里的函数

try...{
if (NULL != sh)

...{
char *str;
str = (char *)env->GetStringUTFChars(s,0);
(*sh)(str);
env->ReleaseStringUTFChars(s,str);
}
FreeLibrary(hinst);

}catch(...)...{
cout<<"exception"<<endl;
}
}
public
class
j_dll
...
{
// Java调用dll

static ...{

try ...{
System.loadLibrary("j_dll");

} catch (Error e) ...{
System.exit(0);
}
}
public native void sayHello(String name);


public static void main(String[] args) ...{
// TODO Auto-generated method stub
j_dll jd = new j_dll();
jd.sayHello("TOM");
}
}
使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。
说白了就是让JAVA和其他语言开的东西进行交互,这里通过一个实例着重介绍下,如何通过JNI使JAVA可以调用本地的DLL。
实例描述:假定现在有一个现成的DLL文件,(这种情况在项目开发中很容易遇到,比如说客户方原来有个老系统,是用C/C++等来开发的,一堆写好的DLL,而如果在功能需求方面没有变化的提前下,利用这些DLL能给项目省下不少工夫),DLL的源文件已经找不到了,通过dump查看只有一个sayHello方法,输入一个名字,如Tom,输出Hello Tom!(当然为了实现这个例子,这个DLL还是要先写出来,但现实中,这个DLL往往是现成了,无需改变,也没法改变)。目前的需求是这样的,在JAVA程序实现:输入一个Tom,调用这个DLL,输出Hello Tom!
实现思路:众所周知,JAVA是不能直接调用DLL文件,不过可以通过JNI,生成一个四不像的DLL,这个DLL既能用JAVA语法,又能与C/C++开发出来的DLL进行交互。于是我们可以通过JAVA调用这个四不像的DLL1,然后在这个DLL1中调用现成的DLL2,实现整个过程,如下图:

具体实现:
1。写一个简单的C++程序,生成那个现成的DLL2,名为c_dll.cpp,实现sayHello这个方法,代码如下:










































通过命令或IDE将其编译成DLL文件,如命令提示符下:
cl
/
c c_dll.cpp
link
/
dll c_dll.obj


生成dll文件c_dll.dll。
2。写一个简单的java类,声明一个由native修饰的方法sayHello(),代码如下:










这里native修饰的sayHello方法就是java调用本地dll的程序入口。
3。通过JNI将这个java类编译成充当桥梁作用的DLL1,具体步骤如下:
1)先用命令生成头文件j_dll.h,命令提示符下进入java类的目录,执行:


就会生成一个名为j_dll.h的头文件,这个文件对于生成DLL1来说是必需的。j_dll.h如下:

























(JNIEnv *, jobject, jstring);方法就是按照java类中的sayHello方法生成的。
2)生成DLL1,新建一个名为j_dll.cpp的文件,代码如下:









































注意开始要引入进来j_dll.h文件,关键代码有写注释,然后按照生成DLL2的方法生成DLL1,名为j_dll.dll(具体方法略)。
4。补全j_dll.java的代码,如下:






















编译java类,运行之,输出Hello Tom。
这样,整个JAVA调用中间层DLL,中间层DLL调用现成的DLL就完成了,是不是很简单呢?希望喜欢JAVA的朋友一起交流哦!