众所周知,Java程序的最大特点就是其跨平台的特性,编写的上层应用程序可以不加任何修改甚至不用重新编译而运行于不同的平台上,然而,Java本身也存着这一个弊端,那就是性能上相对要差一些,在对性能要求比较高的场合,Java程序往往有些力不从心。为了弥补这个缺陷,Java提供了一个叫做JNI的接口技术,Java程序可以通过JNI调用C/C++的库,这对于那些对性能要求比较高的Java程序而言无疑是一个福音。
JNI(Java nativeinterface)可译为Java原生接口,是用来使Java代码能够调用C/C++代码的一种机制。JNI的强大特性使我们在使用JAVA平台的同时,还可以重用原来的本地代码。作为虚拟机实现的一部分,JNI允许JAVA和本地代码间的双向交互。
但是,有一点必须明确,那就是使用JNI也是有代价的。大家都知道Java程序是运行在Java虚拟机JVM之上的,故而可以做到平台无关。但是如果Java程序通过JNI调用了原生的代码(比如c/c++等),则Java程序就丧失了平台无关性。最起码需要重新编译原生代码部分。所以使用JNI需要好好权衡,不到万不得已,请不要选择JNI,可以选择替代方案,比如TCP/IP进行进程间通讯等等。这也是为什么谷歌的Android平台的底层虽然用JNI实现,但是他不建议开发人员用JNI来开发Android上面的应用的原因。因为使用JNI将会丧失Android上面的应用程序平台无关性。
为了能够循序渐进的学习,本文仅仅讨论基于标准Java平台的JNI代码的编写,教JNI的初次接触者能够快速编写出最简单的JNI代码,体验JNI开发的流程。
下面就跟我一起一步一步学习如何使用JNI技术。
研究JNI我认为最好的方法就是从例子入手,就从众所周知的HelloWorld入手吧。
下面我就用JNI实现一个经典的“HelloWorld”程序,该程序在Java中通过JNI调用c函数实现“HelloWorld”的输出。
创建该程序分为以下步骤:
①.创建一个Java程序(HelloWorld.java)定义原生的c/c++函数
②.用javac编译HelloWorld.java生成HelloWorld.class
③.用javah带-jni参数编译HelloWorld.class生成HelloWorld.h文件,该文件中定义了c的函数原型。在实现c函数的时候需要
④.创建HelloWorld.c,实现HelloWorld.h定义的函数
⑤.编译HelloWorld.c生成libHelloWorld.so
⑥.在java虚拟机运行java程序HelloWorld
1.创建Java源程序文件HelloWorld.java
public class HelloWorld{
private native void print();
public static void main(String[] args){
new HelloWorld().print();
}
static {
System.loadLibrary("HelloWorld");
}
}
对上面代码进行简单说明:
①.private native void print()语句只是个函数的声明,而函数的实现并没有在java代码中,关键字native告诉编译器该方法实在本地实现的,我们可以使用该关键字声明一些方法,然后将该方法在本地以C/C++等语言实现并按特定格式编译成动态库,供java程序调用;
②.在本地实现的函数编译成动态库之后,java程序如何识别并加载?后面的static代码段正是实现这个功能,其中的HelloWorld便是动态库的名字,按照动态库的加载规则,我们编译的动态库全名应该为libHelloWorld.so。(待续)