JNI:Java程序(VM)与本地函数的双向接口(调用通道)

(1)Java --JNI通道-->本地函数(JNI函数)

(2)本地程序--JNI通道的JNI接口-->Java


JNI使Java丧失跨平台性(本地程序需重新编译)  


本地函数通过JNI以Java机制与VM交互,而不是C/C++规则

 

使用本地函数实现类库没有实现或效率更高的本地功能,最后通过JNI与VM交互

 

利用JNI函数,程序员可从一个固有方法的内部与JVM打交道。正如大家在前面的例子中看到的那样,每个JNI固有方法都会接收一个特殊的自变量作为自己的第一个参数:JNIEnv自变量——它是指向类型为JNIEnv_的一个特殊JNI数据结构的指针。JNI数据结构的一个元素是指向由JVM生成的一个数组的指针;该数组的每个元素都是指向一个JNI函数的指针。可从固有方法的内部发出对JNI函数的调用,做法是撤消对这些指针的引用(具体的操作实际很简单)。每种JVM都以自己的方式实现了JNI函数,但它们的地址肯定位于预先定义好的偏移处。

利用JNIEnv自变量,程序员可访问一系列函数。这些函数可划分为下述类别:

  • 传递或返回数据
  • 操作实例变量或调用使用垃圾回收的堆中对象的方法
  • 操作类变量或调用类方法
  • 操作数组
  • 对堆中对象加锁,以便被当前线程独占
  • 创建对象
  • 加载类
  • 抛异常
  • 捕获本地方法调用的Java方法抛出的异常
  • 捕获虚拟机异常
  • 告诉垃圾回收器某个对象不再需要

JNI函数的数量相当多,这里不再详述。相反,我会向大家揭示使用这些函数时背后的一些基本原理。欲了解更详细的情况,请参阅自己所用编译器的 JNI文档。

若观察一下jni.h头文件,就会发现在#ifdef _cplusplus预处理器条件的内部,当由C++编译器编译时,JNIEnv_结构被定义成一个类。这个类包含了大量内嵌函数。通过一种简单而且熟悉的语法,这些函数让我们可以从容访问JNI函数。例如,前例包含了下面这行代码:


(*jEnv)->ReleaseStringUTFChars(jEnv, jMsg,msg);


它在C++里可改写成下面这个样子:


jEnv->ReleaseStringUTFChars(jMsg,msg);


大家可注意到自己不再需要同时撤消对jEnv的两个引用,相同的指针不再作为第一个参数传递给JNI函数调用。在这些例子剩下的地方,我会使用 C++风格的代码。