Java语言本身是通过Java的虚拟机解释执行的,因此对于Java中调用本地动态链接库的问题便提上了日程,为何会存在这样的需求呢?因为Java本身的机制导致一些要求高效率的程序难以通过Java来实现(应该说是目前的状态下,理论来讲Java的运行效率是可以达到C的运行效率的,不过目前并没有进入到这个状态),因此很多程序开发者便希望把某一些运行效率要求很高的程序通过Java来实现。
此外还有一些程序是需要调用与硬件相关的底层操作的,而这一点对于Java而言是一个难以逾越的鸿沟,此时为了能够让Java完成同样的功能,只能通过利用C这样的本地编译语言来完成局部任务,最后由Java对这些模块进行调用。所以在Java中如何对本地的DLL进行调用便成了Java开发过程中的一个画龙点睛的技术小亮点了,到底如何完成这一个任务呢?下面来通过一个例子带您掌握这一个不错的小技术。
假设我们目前有一个Java的类,这个类中需要使用到DLL中的方法,于是我们可以将DLL中的方法在Java类中进行一个本地化声明,然后在使用之前,通过Java的程序加载DLL动态链接,这样执行到本地方法时,虚拟机会从已加载的DLL中寻找到被Java调用的本地方法,并执行它。具体的代码如下:
public class TestJNI {
//这里把要调用的DLL中的方法在类中进行一个申明
public static native int add(int n1, int n2);
static {
//在类被加载的时候,通过程序加载相关的DLL
//参数中为被加载的DLL的文件名,不需要包含.dll
//dll需要放置到能够被虚拟机找到的目录中
System.loadLibrary("testjni");
}
public static void main(String args[]) {
//这里直接调用相关的DLL中的方法
int res = TestJNI.add(4, 5);
System.out.println(res);
}
}
好了,我们有了上面的Java代码,接下来需要产生能够被它调用的C++的代码来生成DLL,为了能够生成一致的DLL,我们首先需要产生定义与Java众的需求描述一直的程序头文件。在做这件事情之前,我们首先需要编译定义了本地方法的类文件,产生.class文件,比如说针对上面的例子,我们编译产生了TestJNI.class文件,接下来,我们可以利用JDK为我们提供的一个工具javah.exe来针对刚刚产生的class文件来生成用于动态链接库的.h文件。命令如下:
javah TestJNI
然后查看class文件的目录中,你会发现多了一个TestJNI.h的C头文件,把这个文件添加到生成DLL的C的项目中。然后编写对应的方法的实现文件TestJNI.cpp,这个文件的代码如下:
#include "TestJNI.h"
//动态链接库的入口函数
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//Java中需要调用的方法在C中的具体实现
JNIEXPORT jint JNICALL Java_TestJNI_add
(JNIEnv * env, jclass cls, jint n1, jint n2)
{
jint res = n1 + n2;
return res;
}
好了,代码准备好之后,你可以编译C的代码生成最后的dll文件,将dll的文件改名为testjni.dll。接下来将dll文件放置到系统path变量所指定的任何目录中,运行刚才编译好的java类,任务完成了,你可以看到java对c的调用的最后结果了。
(文中没有讲述如何使用c编写动态链接库的过程,不熟悉的朋友可以参考相关的教程)
此外还有一些程序是需要调用与硬件相关的底层操作的,而这一点对于Java而言是一个难以逾越的鸿沟,此时为了能够让Java完成同样的功能,只能通过利用C这样的本地编译语言来完成局部任务,最后由Java对这些模块进行调用。所以在Java中如何对本地的DLL进行调用便成了Java开发过程中的一个画龙点睛的技术小亮点了,到底如何完成这一个任务呢?下面来通过一个例子带您掌握这一个不错的小技术。
假设我们目前有一个Java的类,这个类中需要使用到DLL中的方法,于是我们可以将DLL中的方法在Java类中进行一个本地化声明,然后在使用之前,通过Java的程序加载DLL动态链接,这样执行到本地方法时,虚拟机会从已加载的DLL中寻找到被Java调用的本地方法,并执行它。具体的代码如下:
public class TestJNI {
//这里把要调用的DLL中的方法在类中进行一个申明
public static native int add(int n1, int n2);
static {
//在类被加载的时候,通过程序加载相关的DLL
//参数中为被加载的DLL的文件名,不需要包含.dll
//dll需要放置到能够被虚拟机找到的目录中
System.loadLibrary("testjni");
}
public static void main(String args[]) {
//这里直接调用相关的DLL中的方法
int res = TestJNI.add(4, 5);
System.out.println(res);
}
}
好了,我们有了上面的Java代码,接下来需要产生能够被它调用的C++的代码来生成DLL,为了能够生成一致的DLL,我们首先需要产生定义与Java众的需求描述一直的程序头文件。在做这件事情之前,我们首先需要编译定义了本地方法的类文件,产生.class文件,比如说针对上面的例子,我们编译产生了TestJNI.class文件,接下来,我们可以利用JDK为我们提供的一个工具javah.exe来针对刚刚产生的class文件来生成用于动态链接库的.h文件。命令如下:
javah TestJNI
然后查看class文件的目录中,你会发现多了一个TestJNI.h的C头文件,把这个文件添加到生成DLL的C的项目中。然后编写对应的方法的实现文件TestJNI.cpp,这个文件的代码如下:
#include "TestJNI.h"
//动态链接库的入口函数
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//Java中需要调用的方法在C中的具体实现
JNIEXPORT jint JNICALL Java_TestJNI_add
(JNIEnv * env, jclass cls, jint n1, jint n2)
{
jint res = n1 + n2;
return res;
}
好了,代码准备好之后,你可以编译C的代码生成最后的dll文件,将dll的文件改名为testjni.dll。接下来将dll文件放置到系统path变量所指定的任何目录中,运行刚才编译好的java类,任务完成了,你可以看到java对c的调用的最后结果了。
(文中没有讲述如何使用c编写动态链接库的过程,不熟悉的朋友可以参考相关的教程)