java调用本地函数_《Java 本地接口规范》- 调用 API | 学步园

本文介绍了如何使用Java调用API在本地程序中嵌入Java虚拟机,通过C++示例展示了创建、连接、断开和卸载虚拟机的过程,以及初始化参数的设置。API函数如JNI_CreateJavaVM、AttachCurrentThread和DestroyJavaVM等在Java虚拟机的嵌入中起到关键作用。
摘要由CSDN通过智能技术生成

调用 API

调用 API 允许软件厂商将 Java 虚拟机加载到任意的本地程序中。厂商可以交付支持 Java 的应用程序,而不必链接 Java 虚拟机源代码。

本章首先概述了调用 API。然后是所有调用 API 函数的引用页。

若要增强 Java 虚拟机的嵌入性,可以用几种方式来扩展 JDK 1.1.2 中的调用 API。

概述

以下代码示例说明了如何使用调用 API 中的函数。在本例中,C++ 代码创建 Java 虚拟机并且调用名为 Main.test 的静态方法。为清楚起见,我们略去了错误检查。

#include        /* 其中定义了所有的事项 */

...

JavaVM *jvm;       /* 表示 Java 虚拟机*/

JNIEnv *env;       /* 指向本地方法接口的指针 */

JDK1_1InitArgs vm_args; /* JDK 1.1 虚拟机初始化参数 */

vm_args.version = 0x00010001; /* 1.1.2 中新增的:虚拟机版本 */

/* 获得缺省的初始化参数并且设置类

* 路径 */

JNI_GetDefaultJavaVMInitArgs(&vm_args);

vm_args.classpath = ...;

/* 加载并初始化 Java 虚拟机,返回 env 中的

* JNI 接口指针 */

JNI_CreateJavaVM(&jvm, &env, &vm_args);

/* 用 JNI 调用 Main.test 方法 */

jclass cls = env->FindClass("Main");

jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");

env->CallStaticVoidMethod(cls, mid, 100);

/* 结束。*/

jvm->DestroyJavaVM();

本例使用了 API 中的三个函数。调用 API 允许本地应用程序用 JNI 接口指针来访问虚拟机特性。其设计类似于 Netscape 的 JRI 嵌入式接口。

创建虚拟机

JNI_CreateJavaVM() 函数加载并初始化Java 虚拟机,然后将指针返回到 JNI 接口指针。调用 JNI_CreateJavaVM() 的线程被看作主线程。

连接虚拟机

JNI 接口指针 (JNIEnv) 仅在当前线程中有效。如果另一个线程需要访问 Java 虚拟机,则该线程首先必须调用AttachCurrentThread() 以将自身连接到虚拟机并且获得 JNI 接口指针。连接到虚拟机之后,本地线程的工作方式就与在本地方法内运行的普通 Java 线程一样了。本地线程保持与虚拟机的连接,直到调用

DetachCurrentThread() 时才断开连接。

卸载虚拟机

主线程不能自己断开与虚拟机的连接。而是必须调用DestroyJavaVM() 来卸载整个虚拟机。

虚拟机等到主线程成为唯一的用户线程时才真正地卸载。用户线程包括 Java 线程和附加的本地线程。之所以存在这种限制是因为 Java 线程或附加的本地线程可能正占用着系统资源,例如锁,窗口等。虚拟机不能自动释放这些资源。卸载虚拟机时,通过将主线程限制为唯一的运行线程,使释放任意线程所占用系统资源的负担落到程序员身上。

初始化结构

不同的 Java 虚拟机实现可能会需要不同的初始化参数。很难提出适合于所有现有和将来的 Java 虚拟机的标准初始化结构。作为一种折衷方式,我们保留了第一个域 (version) 来识别初始化结构的内容。嵌入到 JDK 1.1.2 中的本地应用程序必须将版本域设置为

0x00010001。尽管其它实现可能会忽略某些由 JDK 所支持的初始化参数,我们仍然鼓励虚拟机实现使用与 JDK 一样的初始化结构。

0x80000000 到 0xFFFFFFFF 之间的版本号需保留,并且不为任何虚拟机实现所识别。

以下代码显示了初始化 JDK 1.1.2 中的 Java 虚拟机所用的结构。

typedef struct JavaVMInitArgs {

/* 前两个域在 JDK 1.1 中保留,并

在 JDK 1.1.2 中正式引入。*/

/* Java 虚拟机版本 */

jint version;

/* 系统属性。*/

char **properties;

/* 是否检查 Java 源文件与已编译的类文件

*之间的新旧关系。*/

jint checkSource;

/* Java 创建的线程的最大本地堆栈大小。*/

jint nativeStackSize;

/* 最大 Java 堆栈大小。*/

jint javaStackSize;

/* 初始堆大小。*/

jint minHeapSize;

/* 最大堆大小。*/

jint maxHeapSize;

/* 控制是否校验 Java 字节码:

* 0 无,1 远程加载的代码,2 所有代码。*/

jint verifyMode;

/* 类加载的本地目录路径。*/

const char *classpath;

/* 重定向所有虚拟机消息的函数的钩子。*/

jint (*vfprintf)(FILE *fp, const char *format,

va_list args);

/* 虚拟机退出钩子。*/

void (*exit)(jint code);

/* 虚拟机放弃钩子。*/

void (*abort)();

/* 是否启用类 GC。*/

jint enableClassGC;

/* GC 消息是否出现。*/

jint enableVerboseGC;

/* 是否允许异步 GC。*/

jint disableAsyncGC;

/* 三个保留的域。*/

jint reserved0;

jint reserved1;

jint reserved2;

} JDK1_1InitArgs;

在 JDK 1.1.2 中,初始化结构提供了钩子,这样在虚拟机终止时,本地应用程序可以重定向虚拟机消息并获得控制权。

当本地线程与JDK 1.1.2 中的 Java 虚拟机连接时,以下结构将作为参数进行传递。实际上,本地线程与 JDK 1.1.2 连接时不需要任何参数。JDK1_1AttachArgs 结构仅由 C 编译器的填充槽组成,而 C 编译器不允许空结构。

typedef struct JDK1_1AttachArgs {

/*

* JDK 1.1 不需要任何参数来附加

* 本地线程。此处填充的作用是为了满足不允许空结构的 C

* 编译器的要求。

*/

void *__padding;

} JDK1_1AttachArgs;

调用 API 函数

JavaVM 类型是指向调用 API 函数表的指针。以下代码示例显示了这种函数表。

typedef const struct JNIInvokeInterface *JavaVM;

const struct JNIInvokeInterface ... = {

NULL,

NULL,

NULL,

DestroyJavaVM,

AttachCurrentThread,

DetachCurrentThread,

};

注意,JNI_GetDefaultJavaVMInitArgs()、JNI_GetCreatedJavaVMs() 和JNI_CreateJavaVM()这三个调用 API 函数不是 JavaVM 函数表的一部分。不必先有

JavaVM 结构,就可以使用这些函数。

JNI_GetDefaultJavaVMInitArgs

jintJNI_GetDefaultJavaVMInitArgs(void *vm_args);

返回 Java 虚拟机的缺省配置。在调用该函数之前,平台相关代码必须将 vm_args->version 域设置为它所期望虚拟机支持的 JNI 版本。在 JDK 1.1.2 中,必须将

vm_args->version 设置为 0x00010001。(JDK1.1 不要求平台相关代码设置版本域。为了向后兼容性,如果没有设置版本域,则 JDK 1.1.2 假定所请求的版本为 0x00010001。JDK 的未来版本将要求把版本域设置为适当的值。) 该函数返回后,将把vm_args->version 设置为虚拟机支持的实际 JNI 版本。

参数:

vm_args:指向 VM-specific initialization(特定于虚拟机的初始化)结构的指针,缺省参数填入该结构。

返回值:

如果所请求的版本得到支持,则返回“0”;如果所请求的版本未得到支持,则返回负数。

JNI_GetCreatedJavaVMs

jintJNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen,

jsize *nVMs);

返回所有已创建的Java 虚拟机。将指向虚拟机的指针依据其创建顺序写入 vmBuf 缓冲区。最多写入 bufLen 项。在 *nVMs 中返回所创建虚拟机的总数。

JDK 1.1 不支持在单个进程中创建多个虚拟机。

参数:

vmBuf:指向将放置虚拟机结构的缓冲区的指针。

bufLen:缓冲区的长度。

nVMs:指向整数的指针。

返回值:

成功时返回“0”;失败则返回负数。

JNI_CreateJavaVM

jintJNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env,

void *vm_args);

加载并初始化Java 虚拟机。当前线程成为主线程。将env 参数设置为主线程的 JNI 接口指针。

JDK 1.1.2 不支持在单个进程中创建多个虚拟机。必须将 vm_args 中的版本域设置为 0x00010001。

参数:

p_vm:指向位置(其中放置所得到的虚拟机结构)的指针。

p_env:指向位置(其中放置主线程的 JNI 接口指针)的指针。

vm_args: Java 虚拟机初始化参数。

返回值:

成功时返回“0”;失败则返回负数。

DestroyJavaVM

jintDestroyJavaVM(JavaVM *vm);

卸载 Java 虚拟机并回收资源。只有主线程能够卸载虚拟机。调用 DestroyJavaVM() 时,主线程必须是唯一的剩余用户线程。

参数:

vm:将销毁的 Java 虚拟机。

返回值:

成功时返回“0”;失败则返回负数。

JDK 1.1.2 不支持卸载虚拟机。

AttachCurrentThread

jintAttachCurrentThread(JavaVM *vm, JNIEnv **p_env,

void *thr_args);

将当前线程连接到 Java 虚拟机。在 JNIEnv 参数中返回 JNI 接口指针。

试图连接已经连接的线程将不执行任何操作。

本地线程不能同时连接到两个 Java 虚拟机上。

参数:

vm:当前线程所要连接到的虚拟机。

p_env:指向位置(其中放置当前线程的 JNI 接口指针)的指针。

thr_args:特定于虚拟机的线程连接参数。

返回值:

成功时返回“0”;失败则返回负数。

DetachCurrentThread

jintDetachCurrentThread(JavaVM *vm);

断开当前线程与 Java 虚拟机之间的连接。释放该线程占用的所有 Java 监视程序。通知所有等待该线程终止的 Java 线程。

主线程(即创建 Java 虚拟机的线程)不能断开与虚拟机之间的连接。作为替代,主线程必须调用 JNI_DestroyJavaVM() 来卸载整个虚拟机。

参数:

vm:当前线程将断开连接的虚拟机。

返回值:

成功时返回“0”;失败则返回负数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值