前言
翻译初衷,记录 JNI 编程经验以备后查,并奢望以 JNI 为蓝本,写一本更深入的关于虚拟
机的书。真做起来,才发现以现有水平只能仰望这个目标,要达到它,还需要几年积累。
本书没有采用逐字逐句的翻译,更多采用意译,请大家在阅读时多参考原著;对于书中夹
杂的评论,如有伤观感,请大家见谅。
现在有无数优秀的开源项目,以前高深莫测的技术(虚拟机、编译器、操作系统、协议栈
和 IDE...), 我们终于有机会一探究竟了,真令人兴奋。我们学习,我们参与,希望有一
天我们中国人也能创一门牛技术。
感谢 Die...ken 的审稿,他严谨和认真的态度,深感敬佩;哥们儿祝你:天天开心,早结
连理。
感谢老婆。老婆读书时,看见别人写的书总会感谢太太云云,煞是羡慕,总追问:你什么
时候写书感谢我?难!翻译都这么费劲,写书就不知猴年马月了,在这儿感谢一下,糊弄糊
弄得了。
do.chuan@gmail.com
Preface
本书涵盖了 Java Native Interface(JNI)的内容,将探讨以下问题:
• 在一个 Java 项目中集成一个 C/C++库
• 在一个用 C/C++开发的项目中,嵌入 JavaVM
• 实现 Java VM
• 语言互操作性问题,特别是互操作过程中的垃圾回收(GC, garbage collection)和并
发编程(multithreading)
译注
:
JNI(Java Native Interface)是 SUN 定义的一套标准接口,如 Dalvik, Apache Harmony
项目...等 Java 虚拟机,都会实现 JNI 接口,供本地(C/C++)应用与 Java VM 互调。
JNI: 可以供 Java 代码调用本地代码,本地代码也可以调用 Java 代码,即上文列出的第
4 条内容:语言互操作;所以,这是一套完善而功能强大的接口。
可能有朋友听说过 KNI,那是 J2ME VM(CLDC)中定义的一套东西,不如 JNI 强大。
此外,因为 C/C++在系统编程领域的地位,只要打通了与 C/C++的接口,就等于是天堑变
通途。
首先,通过本书,你会很容易的掌握 JNI 开发,并能了解到方方面面的关于 JNI 的知识。
本书详尽的叙述,会带给你你很多如何高效使用 JNI 的启示。JNI 自 1997 年初发布以来,
Sun 的工程师们和 Java 社区使用 JNI 的经验造就了本书。
第二,本书介绍了 JNI 的设计原理。这些原理,不仅会使学术界感兴趣,也是高效使用
JNI 的前提。
第三,本书的某些部分是 Java 2 平台规范的最终版本。 JNI 程序员可以此书作为规范的
参考手册,Java 虚拟机实现者必须遵循规范,以保证各平台实现的一致性。
(...几段不重要,未翻译...)
CHAPTER 1
Introduction
JNI 是 Java 平台中的一个强大特性。
应用程序可以通过 JNI 把 C/C++代码集成进 Java 程序中。通过 JNI,开发者在利用 Java 平
台强大功能的同时,又不必放弃对原有代码的投资;因为 JNI 是 Java 平台定义的规范接口,
当程序员向 Java 代码集成本地库时,只要在一个平台中解决了语言互操作问题,就可以把
该解决方案比较容易的移植到其他 Java 平台中。
译注
:
比如为 Dalvik 添加了一个本地库,也可以把这个本地库很容易的移植到 J2SE 和 Apache
Harmony 中,因为在 Java 与 C/C++互操作方面,大家都遵循一套 API 接口,即 JNI。
本书由下列三个部分组成:
• Chapter 2 通过简单示例介绍了 JNI 编程
• Chapter 3-10,对 JNI 各方面特性和功能做介绍,并给出示例(译者:重要)
• Chapters 11-13, 罗列 JNI 所有的数据类型的定义
(...几段不重要,未翻译...)
1.1 The Java Platform and Host Environment
因本书覆盖了 Java 和本地(C, C++, etc...)编程语言,让我们首先理一理这些编程语言
的适用领域。
Java 平台(Java Platform)的组成:Java VM 和 Java API. Java 应用程序使用 Java 语言
开发,然后编译成与平台无关的字节码(.class 文件)。 Java API 由一组预定义的类组成。
任何组织实现的 Java 平台都要支持:Java 编程语言,虚拟机,和 API(译者:Sun 对 Java 语
言、虚拟机和 API 有明确规范)。
平台环境: 操作系统,一组本机库,和 CPU 指令集。本地应用程序, 通常依赖于一个特定
的平台环境, 用 C、C++等语言开发,并被编译成平台相关的二进制指令,目标二进制代码
在不同 OS 间一般不具有可移植性。
Java 平台(Java VM 和 Java API)一般在某个平台下开发。 比如,Sun 的 Java Runtime
Environment(JRE)支持类 Unix 和 Windows 平台. Java 平台做的所有努力,都为了使程序更
具可移植性。
1.2 Role of the JNI
当 Java 平台部署到本地系统中,有必要做到让 Java 程序与本地代码协同工作。 部分是
由于遗留代码(保护原有的投资)的问题(一些效率敏感的代码用 C 实现,但现在 JavaVM 的执
行效率完全可信赖),工程师们很早就开始以 C/C++为基础构建 Java 应用,所以,C/C++代码
将长时间的与 Java 应用共存。
JNI 让你在利用强大 Java 平台的同时,使你仍然可以用其他语言写程序。 作为 JavaVM 的
一部分,JNI 是一套双向的接口,允许 Java 与本地代码间的互操作。
如图 1.1 所示
作为双向接口,JNI 支持两种类型本地代码:本地库和本地应用。
• 用本地代码实现 Java 中定义的 native method 接口,使 Java 调用本地代码
• 通过 JNI 你可以把 Java VM 嵌到一个应用程序中,此时 Java 平台作为应用程序的增
强,使其可以调用 Java 类库
比如,在浏览器中运行 Applet, 当浏览器遇到"Applet"标签,浏览器就会把标签中的内
容交给 Java VM 解释执行,这个实现,就是典型的把 JavaVM 嵌入 Browser 中。
译注
:
JNI 不只是一套接口,还是一套使用规则。 Java 语言有"native"关键字,声明哪些方法
是用本地代码实现的. 翻译的时候,对于"native method",根据上下文意思做了不同处理,
当 native method 指代 Java 中用"native"关键字修饰的那些方法时,不翻译;而当代码用
C/C++实现的部分翻译成了本地代码。
上述,在应用中嵌入 Java VM 的方法,是用最少的力量,为应用做最强扩展的不二选择,
这时你的应用程序可以自由使用 Java API 的所有功能;大家有兴趣可以读一读浏览器是怎
么扩展 Applet 的,或者读一读 Palm WebOS 的东西。
译者最近一年都在做这件事,对这个强大的功能,印象特别深刻. 我们整个小组做了两
个平台的扩展,设计、编码、测试和 debug 用了近一年半时间,代码量在 14000 行左右,
做完扩展后,平台功能空前增强。我感觉做软件,难得不在编码,难在开始的设计和后期
的测试、调试和优化,并最终商用,这就要求最终产品是一个强大而稳定的平台,达到此
目标是个旷日持久的事. 看看 Java,Windows,Linux,Qt,WebKit 发展了多少年?
向所有软件工程师致敬!
1.3 Implications of Using the JNI
请记住,当 Java 程序集成了本地代码,它将丢掉 Java 的一些好处。
首先,脱离 Java 后,可移植性问题你要自己解决,且需重新在其他平台编译链接本地库。
第二,要小心处理 JNI 编程中各方面问题和来自 C/C++语言本身的细节性问题,处理不当,
应用将崩溃。
一般性原则:做好应用程序架构,使 native methods 定义在尽可能少的几个类里。
译注
:
学习 JNI 编程是个漫长的实践过程,会碰到无数问题。
用 C/C++编程,常见问题有内存泄露,指针越界...,此外使用了 JNI,还要面对 JavaVM
的问题:
• 在本地代码中 new 一个 Java 对象后期望在本地代码中维护此对象的引用,如何避免
被 GC?
• Java 面向对象语言的封装性被破坏了,Java 类中任何方法和属性对 JNI 都是可见的,
不管它是 public 的,还是 private/protected/package 的
• 对 LocalRef/GlobalRef 管理不善,会引发 Table Overflow Exception,导致应用崩
溃
• 从 JNI 调用 Java 的过程不是很直观,往往几行 Java 代码能搞定的事情,用 JNI 实现
却要几百行
虽然,有这样多问题,逃避不了,你就认了吧。 经过一段时间的实践,当你能熟练处理
这些问题时,就会,眉头一皱,文思泉涌,指尖飞舞,瞬间几百行代码诞生了,一个 make
全部编译通过,这时的你肯定已经对 JNI 上瘾了......
1.4 When to Use the JNI
当你准备在项目中使用 JNI 之前,请先考虑一下是否有其他更合适的方案。 上节有关 JNI
缺点的介绍,应该引起你足够的重视。
这里介绍几个不通过 JNI 与其他语言交互的技术: