曾几何时,开发者们为开发跨平台(广义的,即包括类似于Emacs和GVim这样有多个平台版本的软件)的软件,寻找着各种各样的解决方案。对于从UNIX/Linux下面成长起来的软件,使用GCC-Win32编译加上Cygwin环境进而提供一个Win32的版本是天经地义的。Borland发布Linux下面的Kylix——和Delphi非常相似的开发工具,也曾经让开发者激动万分。随着Java的成熟、Bytecode执行效率的提高和占用内存的下降,又一种可供选择的方案浮出水面(虽然Java早就有了,然而近一二年,随着机器性能的提升和Sun自己的努力,J2SE的性能已经完全可以接受,我们才可能把这一方案实施到大中型项目)。本文无意比较每种方案的优劣,只是集中介绍该方案。
一个项目一定会有很多对性能要求很高的地方,这些地方纯粹使用Java是行不通的,需要使用C/C++编译成为更加高效的本地代码。然而,另一方面,如果为此而整个采用C/C++,又会提高开发成本,尤其是考虑跨平台开发的时候——众所周知,在一般的应用方面,C/C++开发成本(比如,开发时间)要高于Java。因此,如果能够结合二者的优点,将是非常好的事情。索性,Java提供了Java Native Interface (JNI),供我们实现这一梦想。下面以MATLAB软件为例进行说明。
学过类似于数学实验、数值分析课程的同学都知道MATLAB。MATLAB就是这方面的典型——MATLAB的整体结构,界面甚至Document Browser都是由Java完成,而核心的算法则是native C/C++,甚至汇编(MATLAB的BLAS库按照不同CPU调用不同的库,Windows下面表现为不同DLL)。也正是因为如此,MATLAB 6.x的速度一直为我们所“不齿”:),因为其使用的JVM是J2RE 1.3.x(汗);然而随着MATLAB 7.0.1的发布,默认使用J2RE 1.4.2_04(被我换成了1.4.2_05),性能有了很大的提高。加上平均硬件水平的提高,现在MATLAB7.0.1的性能方面已经非常出色了。我没有具体测评,但是感觉非常明显(不仅是我,其他同学也是),另外这也不是本文的重点。
笔者认为,MATLAB很好的实现了开发成本和性能的折中,其方案非常值得我们学习(尤其是对大中型项目开始进行整体设计的时候)。MATLAB是名副其实的跨平台软件,而其基于Java的整体设计、native C/C++甚至基于不同CPU的核心算法库,保证了这一点。运行MATLAB,我们所看到的MATLAB Desktop是拿Swing做的;我们对一个array进行查看、编辑,我们打开Document Browser查文档,我们编辑m程序,这些,都是基于Swing的。MATLAB本身对于XML文件的解析,也是使用了Java提供的模块。这就保证了MATLAB在GUI等方面具有完全的跨平台特性——MATLAB开发者不会在这方面多费功夫了。我们再来看看哪些是native的:当plot一个图的时候,图本身是native的(但是图所在的窗口是Swing的);当执行核心算法的时候,他们最终也是调用了MATLAB核心运算库,这些,也是native的,不仅是platform-dependent,而且CPU-dependent。我们可以看到,MATLAB对于最需要效率的地方,毫不含糊的使用JNI的接口调用native模块,而编写和测试这些native的模块,又完全可以和整体分开进行,这在开发和调试上面是非常有利的。注:plot画图必须native,是因为画3D立体图的时候使用了OpenGL硬件加速。
我再简单的举另一个例子:Jake2,一个Quake2的Java版本,性能极其优异,在AMD Athlon XP 2400, Geforce4 MX, Windows 2000, 800x600 fullscreen下,可以达到235FPS。(http://www.bytonic.de/html/benchmarks.html)截图:http://www.bytonic.de/html/screenshots.html。Juake2通过JNI调用了native的OpenGL接口,而整体上,包括网络方面Q2协议的实现、数据结构方面的建模和实现等等,均是Java完成的。而其JNI的native OpenGL接口,也做了多个平台的实现(使用的是现成的fastjogl),可以说,这个实现的方案,为其跨平台的开发带来了很大的便利,尽管性能比C/C++有所下降,但是依然非常非常不错了(Quaker们知道2xx的FPS意味着什么)。随着J2SE的成熟,我们可以在不同平台统一的完成窗口各种事件等的跨平台的统一处理,不需要很高效率的GUI组件的绘制和响应等等。
可以说,这些例子对于跨平台的项目实现很具启发。我们可以完全用Java设计出整体的框架以及GUI等,然后native出需要高效实现的method,使用C/C++甚至汇编进行实现。可以说,随着Java的成熟,这种模式一定会使跨平台的大中型项目受益匪浅。你可能会说,不就是JNI嘛!是啊,确实主要就是利用了JNI。然而,JNI本身只是一项技术,本文最重要的目的,1是希望你能够充分意识到存在这样一种模式,以及它的巨大威力(当然,是在经过了优秀的设计的基础上);2是希望告诉你,知道这些优秀的软件是使用JNI的本身没有什么了不起,而是希望你可以从这些软件的设计思想中获得启发,揣摩他们是如何进行设计,如何进行模块化的,哪些部分使用Java,哪些进行native。我想这些是非常重要的。我想,对于像MATLAB这样的软件,其使用Java+JNI的跨平台开发方案,比纯粹C/C++的跨平台开发方案,开发成本一定是低很多的。