JNI是一个本地编程接口。它允许在Java虚拟机(VM)中运行的Java代码与用其他编程语言(如C、C++和汇编)编写的应用程序和库进行互操作。
JNI最重要的优点是它不限制底层JVM的实现。因此,JVM供应商可以添加对JNI的支持,而不会影响JVM的其他部分。程序员可以编写本地应用程序或库的一个版本,并期望它与支持JNI的所有JVM一起工作。
一、JNI综述
虽然可以完全使用Java编写应用程序,但在某些情况下,Java本身无法满足应用程序的需求。当应用程序不能完全用Java编写时,程序员使用JNI编写Java本地方法来处理这些情况。
下面的例子说明了什么时候需要使用Java原生方法:
- 标准Java类库不支持应用程序所需的依赖于平台的特性。
- 已经有了一个用另一种语言编写的库,我们希望Java代码可以通过JNI访问它。
- 希望在较低级别的语言(如汇编语言)中实现一小部分时间敏感的代码。
- 通过JNI编程,可以使用的本地方法:
- 创建、检查和更新Java对象(包括数组和字符串)。
- 调用Java方法。
- 捕获和抛出异常。
- 加载类并获取类信息。
- 执行运行时类型检查。
我们还可以使用JNI和调用API来支持任意的本地应用程序嵌入JVM。这允许程序员轻松地使他们现有的应用程序启用java,而不必链接到VM源代码。
二、历史背景
来自不同供应商的VM提供不同的本地方法接口。这些不同的接口迫使程序员在给定的平台上生成、维护和分发本地方法库的多个版本。
简要介绍了一些本地方法接口,例如:
- JDK 1.0原生方法接口
- Netscape的Java运行时接口
- 微软的原始本地接口和Java/COM接口
三、目标
一个统一的、经过深思熟虑的标准接口为每个人提供了以下好处:
- 每个VM供应商都可以支持更多的本地代码。
- 工具构建器不必维护不同种类的本地方法接口。
- 应用程序程序员将能够编写一个版本的本地代码,这个版本将在不同的VM上运行。
标准的原生方法接口必须满足以下要求:
1.二进制兼容性——主要目标是在给定平台上跨所有Java
2.VM实现的本机方法库的二进制兼容性。对于给定的平台,程序员应该只维护本地方法库的一个版本。
3.效率——为了支持时间敏感型代码,本地方法接口必须施加很少的开销。所有已知的确保VM独立性(以及二进制兼容性)的技术都会带来一定的开销。我们必须在效率和虚拟机独立性之间达成妥协。
4.功能——接口必须公开足够的JVM内部,以允许本地方法完成有用的任务。
四、JNI编程
本地方法程序员应该面向JNI编程。面向JNI编程使程序员免受未知因素的影响,比如最终用户可能正在运行的供应商的VM。通过遵循JNI标准,将为本地库提供在给定JVM中运行的最佳机会。
如果正在实现JVM,那么应该实现JNI。JNI经过了时间测试,确保不会对VM实现施加任何开销或限制,包括对象表示、垃圾收集方案等。
五、副作用
一旦使用JNI,JAVA程序就丧失了JAVA平台的两个优点:
- 程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
- 程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了JAVA和本地代码之间的耦合性。
六、变更
从Java SE 6.0开始,已经删除了不赞成使用的结构JDK1_1InitArgs和JDK1_1AttachArgs,取而代之的是使用JavaVMInitArgs和JavaVMAttachArgs。