JNI Introduction

翻译自 https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html

Chapter   1

本章介绍Java本地接口(JNI)。 JNI是一个本地编程接口。 它允许在Java虚拟机(VM)内运行的Java代码与使用其他编程语言
(如C,C ++和汇编)编写的应用程序和库进行交互操作。

JNI最重要的优点是它对底层Java VM的实现没有任何限制。 因此,Java VM供应商可以添加对JNI的支持,而不会影响VM的其他部分。程序员可以编写一个版本的本地应用程序或库,并预期它可以与所有支持JNI的Java VM配合使用。

Java Native Interface Overview

尽管您可以完全使用Java编写应用程序,但在某些情况下,Java本身并不能满足应用程序的需求。当应用程序不能完全用Java编写时,程序员使用JNI编写Java本地方法来处理这些情况。

以下示例说明何时需要使用Java本地方法:

  •     标准的Java类库不支持应用程序所需的平台相关功能。
  •     你已经有了一个用另一种语言编写的库,并希望通过JNI使它可以被Java代码访问。
  •     您希望用低级语言(如汇编)实现一小部分时序要求严格的代码。


通过通过JNI编程,您可以使用本地方法来:

  •     创建,检查和更新Java对象(包括数组和字符串)。
  •     调用Java方法。
  •     捕捉并抛出异常。
  •     加载类并获取类信息。
  •     执行运行时类型检查。

您还可以将JNI与Invocation API结合使用,以使任意本地应用程序嵌入Java VM。 这使程序员可以轻松地使其现有的应用程序启用Java功能,而不必将源代码链接到VM。

Historical Background

不同的VM厂商提供不同的本地方法接口。这些不同的接口迫使编程人员在给定平台上生成、维护、发布多个版本的本地方法库。
我们简要地回顾一些本地方法接口,例如:

  •     JDK 1.0本地方法接口
  •     Netscape的Java运行时接口
  •     微软的原生本地接口和Java / COM接口

JDK 1.0 Native Method Interface
JDK 1.0附带了一个本地方法接口。 不幸的是,有两个原因使这个接口不适合被其他Java虚拟机采用。
首先,本地代码是将Java对象的字段作为C结构体的成员来访问的。 但是,Java语言规范并未定义对象在内存中的布局方式。 如果Java VM在内存中布置对象发生变化时,那么程序员将不得不重新编译本地方法库。
其次,JDK 1.0的本机方法接口依赖于保守的垃圾收集器。 例如,不受限制地使用了unhand宏,因此有必要保守地扫描本机堆栈。

Java Runtime Interface
Netscape提出了Java运行时接口(JRI),这是Java虚拟机中提供服务的通用接口。 JRI的设计考虑到了可移植性---
它对底层Java VM中的实现细节做了一些假设。 JRI解决了广泛的问题,包括本地方法,调试,反射,嵌入(调用)等等。

Raw Native Interface and Java/COM Interface(原生本地接口和Java / COM接口)
Microsoft Java VM支持两个本地方法接口。在低级别上,它提供了一个高效的原生本地接口(RNI)。 RNI提供了与JDK
本地方法接口高度的源码级别的后向兼容性,尽管有一个主要区别:本地代码不必依赖保守的垃圾收集(GC),而必须使用RNI
函数与垃圾收集器进行显式交互。

在更高层次上,微软的Java / COM接口为Java VM提供了与语言无关的标准二进制接口。 Java代码可以像使用Java对象
一样使用COM对象。 Java类也可以作为COM类暴露给系统的其余部分。

 

Objectives

我们相信统一、成熟的标准接口会为大家提供了如下益处:

  •     每个VM供应商都可以支持更多的本地代码。
  •     工具构建者不必维护不同种类的本地方法接口。
  •     应用程序员将可以编写一个版本的本地代码,并且此版本可以运行在不同的VM上。

实现标准本地方法接口的最佳方式是让对Java VM相关的各方都参与其中。因此,我们在Java许可证持有者之间就统一
本地方法接口的设计组织了一系列讨论。从讨论中可以清楚地看到,标准本地方法接口必须满足以下要求:

  •     二进制兼容性 - 主要目标是跨给定平台上所有的Java VM的的本地方法库的二进制兼容性。程序员应该只为给定平台保留本地方法库的一个版本。
  •     效率 - 为了支持对时序要求严格的代码,本地方法接口必须只能耗费很少的开销。所有已知的确保虚拟机独立性(以及二进制兼容性)的技术都会带来一定的开销。在某种程度上,我们必须在效率和VM独立性之间达成妥协。
  •     功能 - 接口必须暴露足够多的Java虚拟机内部以允许本地方法完成有用的任务。

    
Java Native Interface Approach

我们希望采用现有的方法之一作为标准接口,因为这会给那些必须在不同虚拟机上学习多个接口的程序员造成最小的负担。
遗憾的是,现有的解决方案并不能完全实现我们的目标。

Netscape的JRI与我们设想的便携式本地方法接口最接近,并被用作我们设计的起点。熟悉JRI的读者会注意到有许多相似之处,
比如方法和字段ID的使用,局部引用和全局引用的使用,等等。尽管我们尽了最大的努力,但是,JNI与JRI不是二进制兼容的,
尽管VM可以同时支持JRI和JNI。

微软的RNI是对JDK 1.0的改进,因为它解决了使用非保守垃圾收集器的本地方法的问题。但是,RNI不适合作为独立于VM的本
地方法接口。像JDK一样,RNI本地方法以C结构体的形式访问Java对象,导致两个问题:

  •     RNI将Java对象的数据内部暴露给本地代码。
  •     将Java对象作为C数据结构的直接访问不能有效地与高级垃圾回收算法中必需的“写障碍”(“write barriers)相结合。


作为二进制标准,COM确保跨不同VM的完整二进制兼容性。调用一个COM方法只需要一个间接调用,这个调用的开销很小。另外,相比动态链接库,COM对象在解决版本控制问题方面有了很大的改进。

然而,使用COM作为标准Java本地方法接口受到以下几个因素的限制:

  •     首先,Java/COM接口缺少某些期望的功能,如访问私有字段和引发一般异常。
  •     其次,Java/COM接口自动为Java对象提供标准的IUnknown和IDispatch COM接口,以便本地代码可以访问Java对象的公共方法和字段。不幸的是,IDispatch接口不处理重载的Java方法,并且在匹配方法名称时不区分大小写。此外,通过IDispatch接口公开的所有Java方法都被打包以执行动态类型检查和强制转换。这是因为IDispatch接口是用弱类型语言(如Basic)设计的。
  • 第三,COM被设计为允许软件组件(包括成熟的应用程序)一起工作,而不是处理单个的低级功能。 我们认为将所有Java类或低级本地方法视为软件组件是不合适的。
  •     第四,由于缺乏对UNIX平台的支持,直接使用COM受到阻碍。

尽管Java对象不作为COM对象对本地代码公开,但JNI接口本身与COM是二进制兼容的。 JNI与COM使用相同的跳转表结构和调用约定。这意味着只要跨平台对COM的支持可用,JNI就可以成为Java VM的COM接口。

JNI不被认为是被给定Java VM所唯一支持的本地方法接口。 标准接口使编程者受益,他们希望将他们的本地代码库加载到不同的Java虚拟机中。 在某些情况下,程序员可能不得不使用较低级别的、特定的VM接口来实现最高效。 在其他情况下,程序员可能会使用更高级的界面来构建软件组件。 事实上,随着Java环境和组件软件技术越来越成熟,本地方法将逐渐失去意义。


Programming to the JNI

本地方法程序员应该编写JNI程序。 JNI编程使你免于未知,比如供应商的虚拟机,终端用户可能正在运行它。 通过符合JNI标准,您将会得到为给定的Java VM提供一个本地库运行的最佳时机。

如果你正在实现一个Java虚拟机,你应该实现JNI。 JNI已经过时间测试,并确保不会对你的虚拟机实现施加任何开销或限制,包括对象表示,垃圾回收机制,等等。 如果您遇到任何我们可能忽略的问题,请将您的反馈发送给我们。

Changes

从Java SE 6.0开始,已弃用的结构JDK1_1InitArgs和JDK1_1AttachArgs已被删除,JavaVMInitArgs
和JavaVMAttachArgs将被使用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值