欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

JNI简介,

来源: javaer 分享于  点击 35086 次 点评:76

JNI简介,


JNI 简介 -----Java 调用 C 函数

Java 是面向对象的王牌语言,安全,规范,容易使用和“一次编译,到处运行”等等优点,很快让 Java 成为了世界第一语言。在很多方面, Java 都是无可挑剔的,但当涉及到某个平台的底层时,或需要深入某个操作系统时, Java 就显得力不从心了。幸运的是, Java 提供了调用本地方法的方式,通过 JNI ,可以让 Java 调用 C 语言函数。这为我们提供了很多便利,比如,我们有现成的 C 语言库,不想用 Java 再重写,这时就可以通过 JNI 来实现代码重用。但更重要的,我认为, JNI 可以拓展 Java ,让其完成更多更复杂的操作系统相关的任务。对于 JNI 最常用的应用是用其实现与操作系统密切相关的任务。

JNI 与平常的接口过程没有二样儿,也是二个过程:定义接口和实现接口。只不过接口的定义是在 Java 层,而实现却是在 C 这里要注意,虽然,也可以用 C++ 来实现接口,但是 JNI 只支持标准 C ,对 C++ 的类和 STL ,模板和重载等不提供支持,所以当用 C++ 来实现时,请加上宏 ’extern “C” { }; 以去掉那些 C 不支持的 C++ 特性。

JNI 通常要四个步骤:

<!-- [if !supportLists]-->1. <!-- [endif]-->定义接口

<!-- [if !supportLists]-->2. <!-- [endif]--> C/C++ 实现接口

<!-- [if !supportLists]-->3. <!-- [endif]--> C/C++ 的实现做成共享库 (Windows 平台的 .dll Linux 平台的 .so)

<!-- [if !supportLists]-->4. <!-- [endif]-->集成

下面我们通过一个具体的真正的实例来演示如何实现一个 JNI

问题: 虽然 Java 可以“一次编译,到处运行”,但是由于它对跨平台支持的太好了,所以用 Java 很难分辨出平台之间的差异。比如,我们如果想为 64 位的 Windows 32 Windows 做点不同的东西,那么就需要我们用程序来区分这二个系统,以进行不同的处理。 Java 里面提供了 os.arch 属性,但是这个是针对处理器的,并不是操作系统的。因为有些情况是在 32 位处理器上可能装 64 位的系统,在 64 位处理器也可装 32 位的系统,而我们想要的是操作系统是 64 位还是 32 位,并非处理器。这时就要求助于 JNI 了,用 C 语言通过 Windows 自身的 API 我们是可以很容易得出这个操作系统是 64 位还是 32 位。

实现过程:

<!-- [if !supportLists]-->1. <!-- [endif]-->定义接口: 可以用如下代码来定义 SystemType.java

public class SystemType { public native boolean is64BitSystem(); static { System.loadLibrary(“SystemType”); } }

在这里, public native boolean is64BitSystem(); 就是我们在 Java 层的接口,其他地方可以调用这个接口。下在的语句,是用来告诉 JVM 到哪个库里面去找接口的实现,另外我们还要告诉 JVM ,这个库是放在什么地方(路径),请参见 4 、集成。

<!-- [if !supportLists]-->2. <!-- [endif]-->实现: 这是 JNI 中最关键的,能否完成就在此了。对于 Windows 操作系统的类型( 32-64 ),即使是用 C 也不是很容易的,因为很多常规方法都没有用。通过查找资料我找到了如下方法,通过验证,发现很有用 .

在实现的时候要注意,我们不能对 Java 接口直接进行实现,因为毕竟是二种不同的语言。 C 语言只能实现它自己的接口 ----- 头文件。为此我们必须要把 Java 的接口转化为 C 语言的头文件。如下便可实现:

javac SystemType.java

javah SystemType

如果没有任何错误就会生成一个头文件 SystemType.h ,这就是我们要实现的。注意,如果你的 Java 类是在某个包下面,那么在编译是要注意,一定要在根目录下,用完整的包名来编译,否则会出错。如:

SystemType.java

package util.system;

Public class SystemType { …. }

#pwd

/work/src/util/system

#cd /work/src

#javac util/system/SystemType.java

#javah util.system.SystemType

生成的头文件会是这相样子:

SystemType.h

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class system_type_SystemType */ #ifndef _Included_system_type_SystemType #define _Included_system_type_SystemType #ifdef __cplusplus extern "C" { #endif /* * Class: system_type_SystemType * Method: is64BitWindows * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_system_1type_SystemType_is64BitWindows (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif

SystemType.c

#include "stdafx.h" #include "comutil.h" #include "system_type_SystemType.h" #include <cstdio> #include <Shlobj.h> #include <Shfolder.h> #include <cerrno> extern "C" { #ifdef _MANAGED #pragma managed(push, off) #endif typedef BOOL (WINAPI *IW64PFP)(HANDLE, BOOL *); BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } JNIEXPORT jboolean JNICALL Java_system_1type_SystemType_is64BitWindows (JNIEnv *, jobject) { int res = false; /* * On Windows, we need to open the log in current user's Application Data in which * have the full accesses to write. */ IW64PFP IW64P = (IW64PFP)GetProcAddress( GetModuleHandle(L"kernel32"), "IsWow64Process"); if(IW64P != NULL){ IW64P(GetCurrentProcess(), &res); } return res; } #ifdef _MANAGED #pragma managed(pop) #endif }

<!-- [if !supportLists]-->3. <!-- [endif]-->编译共享库:

Visual Studio 的项目属性改为 dll, 然后编译,还要在 extra include files 选项中把 JDK 提供的 JNI 头文件加上 (jdk /include, jdk /include/win32) ,就得到了我们想要的东西了,剩下的任务就是把这些东西集成起来,让他们工作。

注意:如果是在 Linux 平台下面,则要加上一些选项:

gcc –fPIC –Ijdk /include –Ijdk /include/linux –shared –l libSystemType.so SystemType.c

<!-- [if !supportLists]-->4. <!-- [endif]-->集成: 最后一道工序了,前面提到了,代码中的 System.loadLibrary 是告诉 JVM 到哪个库中去找接口的实现,而在运行的时候要给告诉 JVM ,这个库文件放在哪。因此我们要给 JVM 加上一个参数如

java -Djava.library.path=D:/workspace/MyProject/libs

然后把库放到 D:/workspace/MyProject/libs 就可以了。

这样,一个简单的 JNI 就完成了,当然,还可以用 JNI 实现更复杂的功能。比如可以在 JNI C 实现中使用一些 Java 特性,如抛出异常,还可以使用 Java API 等等,更详细的请参见《 Java 核心编程,卷二,第十一章:本地方法》 .

参考资料: Car S. Horstman, Gary Cornell Java 核心技术,卷二:高级特性》第七版,十一章, 2008

相关文章

    暂无相关文章
相关栏目:

用户点评