JNI 即 Java Native Interface 是 native 编程接口,它允许在Java虚拟机(VM)内运行Java代码与其他编程语言(主要是C和C++)编写的应用程序和库进行交互操作。

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

本文主要将从以下几点讲述JNI相关的内容,用于我们了解JNI:

概述、背景、目标、实现方式。

一、JNI 概述

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

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

  • 标准Java类库不支持应用程序所需的与平台相关的功能。
  • 您已经有一个使用另一种语言编写的库,并希望通过JNI使其可以访问Java代码。
  • 您希望在较低级别的语言(如C/C++)中实现一小部分时间关键代码。

通过JNI编程,您可以使用Native方法:

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

二、JNI 产生的历史背景

来自不同供应商的VM提供了不同的Native方法接口。这些不同的接口迫使程序员在给定平台上生成,维护和分发多个版本的本机方法库。

我们简要介绍一些本机方法接口,例如:

  • JDK 1.0本机方法接口
  • Netscape的Java运行时接口
  • Microsoft的原始本机接口和Java / COM接口

1、JDK 1.0本机方法接口

JDK 1.0 附带了Native方法接口。不幸的是,这个接口不适合其他Java VM采用有两个主要原因。

首先,本机代码访问Java对象中的字段作为C结构的成员。但是,Java语言规没有定义对象在内存中的布局方式。如果Java VM在内存中以不同方式布局对象,则程序员必须重新编译本机方法库。

其次,JDK 1.0的本机方法接口依赖于保守的垃圾收集器。unhand例如,不受限制地使用宏使得必须保守地扫描本机堆栈。

2、Java运行时接口

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

3、原始本机接口和Java / COM接口

Microsoft Java VM支持两种本机方法接口。在低级别,它提供了有效的原始本机接口(RNI)。RNI提供了与JDK本机方法接口的高度源级向后兼容性,尽管它有一个主要区别。本机代码必须使用RNI函数与垃圾收集器明确交互,而不是依赖于保守的垃圾收集。

在更高级别,Microsoft的Java / COM接口为Java VM提供了与语言无关的标准二进制接口。Java代码可以像使用Java对象一样使用COM对象。Java类也可以作为COM类公开给系统的其余部分。

三、JNI 产生的目标

我们相信,统一且经过深思熟虑的标准接口为每个人提供以下好处:

  • 每个VM供应商都可以支持更多的natvie代码。
  • 工具构建器不必维护不同类型的natvie方法接口。
  • 应用程序编程人员将能够编写其natvie代码的一个版本,该版本将在不同的VM上运行。

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

  • 二进制兼容性 - 主要目标是在给定平台上的所有Java VM实现中对本机方法库进行二进制兼容。程序员应该只为给定平台维护其本机方法库的一个版本。
  • 效率 - 为了支持时间关键代码,本机方法接口必须施加很少的开销。确保VM独立性(以及二进制兼容性)的所有已知技术都带有一定量的开销。我们必须以某种方式在效率和VM独立性之间达成妥协。
  • 功能 - 接口必须公开足够的Java VM内部,以允许本机方法完成有用的任务。

四、实现JNI的方式讨论

我们希望采用现有方式之一作为标准,主要是为了给在不同VM中学习多个接口的程序员带来最小的负担。但是令人失望的是,目前没有现有的解决方案来实现我们这样的想法。

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

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

  • RNI将内部Java对象的布局暴露给本机代码。
  • 直接访问Java对象作为C结构使得无法有效地合并“写入障碍”,这在高级垃圾收集算法中是必需的。

作为二进制标准,COM确保跨不同VM的完全二进制兼容性。调用COM方法只需要间接调用,这几乎不会产生任何开销。此外,COM对象在解决版本问题方面比动态链接库有了很大的改进。

但是,使用COM作为标准Java本机方法接口受到以下几个因素的阻碍:

  • 首先,Java / COM接口缺少某些所需的功能,例如访问私有字段和引发一般异常。
  • 其次,Java / COM接口自动为Java对象提供标准的IUnknown和IDispatch COM接口,以便本机代码可以访问公共方法和字段。遗憾的是,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中。在某些情况下,程序员可能必须使用较低级别的VM特定接口来实现最高效率。在其他情况下,程序员可能使用更高级别的界面来构建软件组件。实际上,随着Java环境和组件软件技术的日趋成熟,本机方法将逐渐失去意义。

五、总结

首先本文是译文,原文地址为:https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/intro.html

同时也是本人整理的JNI教程的第一篇,可能部分内容语法有点不通顺,但是看完了也能基本了解JNI是什么,产生的背景,以及JNI被实现的方式。

下面附一下学习JNI时推荐的参考资料:

Android JNI 学习(一):JNI 简介的更多相关文章

  1. Android JNI学习(四)——JNI的常用方法的中文API

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  2. Android JNI学习(二)——实战JNI之“hello world”

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  3. android学习笔记----JNI中的c控制java

    面向对象的底层实现 java作为面向对象高级语言,可对现实世界进行建模.和面向过程不同的是面向对象软件的编写不是流程的堆积,而是对业务逻辑的多视角分解和分类.其过程大致为:      1).将知识分解 ...

  4. Android JNI学习(五)——Demo演示

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  5. Android JNI学习(三)——Java与Native相互调用

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  6. JNI学习笔记_Java调用C —— Android中使用的方法

    一.笔记 1.JNI(Java Native Interface),就是如何使用java去访问C/C++编写的那些库.若想深入了解JNI可以看官方文档jni.pdf.优秀博文:Android JNI知 ...

  7. Android学习笔记--JNI的使用方法

    1.JNI是什么 JNI是Java Native Interface的缩写,它提供若干的API实现Java与其他语言之间的通信.而Android Framework由基于Java语言的的Java层与基 ...

  8. Android学习JNI,使用JNI实现字符串加密

    本节学习使用C语言加密字符串,大家都知道使用JAVA实现的加密都能够反编译的,而使用C写的加密是非常难被反编译的.所以我们使用JNI学习怎样使用C实现对字符串的加密. 首先:我们实现一个界面 布局文件 ...

  9. Android JNI 学习(四):接口方法表 & Base Api & Exception Api

    本文我们来总结一下JNI 提供的功能列表及相关的函数表. 注意:请注意使用术语“必须”来描述对JNI程序员的限制.例如,当您看到某个JNI函数必须接收非NULL对象时,您有责任确保不将NULL传递给该 ...

  10. Android JNI和NDK学习(06)--JNI的数据类型(转)

    本文转自:http://www.cnblogs.com/skywang12345/archive/2013/05/23/3094037.html 本文介绍JNI的数据类型.NDK中关于JNI数据类型的 ...

随机推荐

  1. laravel的路由分组,中间件,命名空间,子域名,路由前缀

    laravel的路由分组,就是把一些具有相同特征的路由进行分组,比如一些路由需要进行验证,一些路由有共同的前缀,一些路由有相同的控制器命名空间等. 这样把路由组合在一起,方便管理,维护性更好. Rou ...

  2. Contours 等高线图

    1.画等高线 数据集即三维点 (x,y) 和对应的高度值,共有256个点.高度值使用一个 height function f(x,y) 生成. x, y 分别是在区间 [-3,3] 中均匀分布的256 ...

  3. day 1:计算机发展史和组成部分

    本节内容: 1,计算机的发展史 2,计算机的组成 1,计算机的发展史 1946年2月14日,由美国军方定制的世界上第一台电子计算机“电子数字积分计算机”(ENIAC Electronic Numeri ...

  4. Finance财务软件(自定义报表专题)

    我们可以通过存储过程自定义报表 1.在菜单中新增报表菜单,这里的代码约束为报表对应存储过程名称,配置完成成后重启客户端生效 2.在自定义模板中适配存储过程入参,这里的功能键值为存储过程名称,字段键值与 ...

  5. Python建立时间事件引擎原理剖析

    作为python小白,学习量化交易的曲线是非常陡峭的,唯一好的办法就是一点点啃代码.以下代码案例来自vnpy的引擎代码. # encoding: UTF-8 #定义时间事件 EVENT_TIMER = ...

  6. 【MyBatis-Spring】Mybatis和并入Spring框架

    1.参考书籍:<深入浅出MyBatis技术原理与实战> 2.知识基础:Spring.Mybatis.Spring MVC. 配置数据源 配置SqlSessionFactory SqlSes ...

  7. XBee模块户外通信距离测试

    Digi的XBee模块在市面上同类产品中,除了稳定性和可靠性最受推崇外,在距离测试中一般都比竞争对手的产品略胜一筹.户外测试需要注意避免模块自身以外的因素造成的测试结果不理想. 2.4G的模块有Zig ...

  8. 使用Mobile Device Manager Plus mdm软件进行完备的移动设备管理

    使用Mobile Device Manager Plus mdm软件进行完备的移动设备管理 什么是移动设备管理(mdm管理系统)? 移动设备管理(mdm管理系统)旨在管理企业内移动设备.管理员使用md ...

  9. Spring RestTemplate get post 请求 携带 headers

    RestTemplate 1.我用RestTemplate请求时 我把他注入到容器里  这样可以 什么用什么时候拿 2.也可以new出来 不过我不喜欢 所以就没有用new的 下面我自己的方法   先注 ...

  10. 用java实现的英汉词典

    import java.io.*; import java.util.*; public class MyDictionary { static private Map<String, Stri ...