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 通常要四个步骤:

1. 定义接口

2. C/C++ 实现接口

3. C/C++ 的实现做成共享库 (Windows 平台的 .dll Linux 平台的 .so)

4. 集成

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

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

实现过程:

1.  定义接口: 可以用如下代码来定义 SystemType.java

             

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

2.  实现: 这是 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

            

SystemType.c

            

3. 编译共享库:

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

4.  集成: 最后一道工序了,前面提到了,代码中的 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

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值