JNI 全称 Java Native Interface。Java本地方法接口,它允许Java应用程序可以调用本地方法(native method),本地方法就是指用本地程序设计语言(C/C 等)编写的特殊方法。
本地方法在本地语言可以中可执行任意的计算任务,并返回Java程序设计语言。
维基百科是这样解释的:“当应用无法完全用Java编程语言实现的时候,(例如,标准Java类库不支持的特定平台特性或者程序库时),JNI使得编程者能够编写native方法来处理这种情况”。
本地方法的用途
本地方法主要提供三种用途:
- 提供“访问特定平台的机制”能力,如访问注册表(registry)和文件锁(file lock)
- 提供“访问遗留代码库”能力,进而访问遗留数据(legacy data)
- 编写应用程序中注重性能的部分,以提高系统的性能
使用本地方法访问特定于平台的机制是合法的。随着JVM的不断成熟,本地方法提供了越来越多以前只有在“宿主”平台才有的特性。例如,java 1.4 发行版新增的java.util.prefs 包就提供了注册表的功能;1.6 发行版增加了 java.awt.SystemTray 提供了访问桌面系统托盘区的能力。
同时,使用本地方法来访问遗留代码也是合法的。
本地方法的重要性在下降
使用本地方法来提高性能的做法不值得提倡。早起的jdk发行版(1.3之前),这样做法是必要的,但JVM实现变得越来越快了。对于大多数任务,现在即使不适应本地方法也能够获得与“使用本地方法”相当的性能了。
- jdk 1.1 发行版增加了java.math 时,BigInteger 是在一个用C 编写的快速多精度运算库的基础上实现的。在当时,为了获取足够的性能,这样子做无可厚非
- 在jdk 1.3之后,BigInteger 完全用Java 重写了,并且进行了精心的性能调优
其二,C/C 编写的程序是非安全的。所以,使用了本地方法的应用程序也不可以避免受到内存毁坏导致的错误。
Java 是一门安全的语言(safe language),因为它对于缓冲区、数组越界、非法指针以及其他的内存破坏错误都自动免疫,而类似内存溢出或者指针异常等问题却始终困扰着C/C 这样的非安全语言。
其三,因为本地语言是平台相关,使用本地方法的应用程序也不再是“自由移植”的。
其四,使用了本地方法的应用程序使得代码调试变得困难,在进入和退出本地方法时,需要额外的固定开销。所以,如果本地方法只是做了少量工作,非但没有起到优化性能的目的,反而降低了性能。
其五,需要“胶合代码”的本地方法编写起来单调乏味,代码可读性也低。
总结
总而言之,使用本地方法前需要三思。随着JVM发展,后面是极少情况下会需要使用本地方法来提高性能的。
如果你必须要使用本地方法来访问底层资源,或者遗留代码库,也要尽可能少用本地代码,并且进行全面测试。因为本地代码的一个Bug 就可能破坏整个应用程序。