Java 本地接口规范Word格式.docx

上传人:b****4 文档编号:6397889 上传时间:2023-05-06 格式:DOCX 页数:84 大小:56.09KB
下载 相关 举报
Java 本地接口规范Word格式.docx_第1页
第1页 / 共84页
Java 本地接口规范Word格式.docx_第2页
第2页 / 共84页
Java 本地接口规范Word格式.docx_第3页
第3页 / 共84页
Java 本地接口规范Word格式.docx_第4页
第4页 / 共84页
Java 本地接口规范Word格式.docx_第5页
第5页 / 共84页
Java 本地接口规范Word格式.docx_第6页
第6页 / 共84页
Java 本地接口规范Word格式.docx_第7页
第7页 / 共84页
Java 本地接口规范Word格式.docx_第8页
第8页 / 共84页
Java 本地接口规范Word格式.docx_第9页
第9页 / 共84页
Java 本地接口规范Word格式.docx_第10页
第10页 / 共84页
Java 本地接口规范Word格式.docx_第11页
第11页 / 共84页
Java 本地接口规范Word格式.docx_第12页
第12页 / 共84页
Java 本地接口规范Word格式.docx_第13页
第13页 / 共84页
Java 本地接口规范Word格式.docx_第14页
第14页 / 共84页
Java 本地接口规范Word格式.docx_第15页
第15页 / 共84页
Java 本地接口规范Word格式.docx_第16页
第16页 / 共84页
Java 本地接口规范Word格式.docx_第17页
第17页 / 共84页
Java 本地接口规范Word格式.docx_第18页
第18页 / 共84页
Java 本地接口规范Word格式.docx_第19页
第19页 / 共84页
Java 本地接口规范Word格式.docx_第20页
第20页 / 共84页
亲,该文档总共84页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Java 本地接口规范Word格式.docx

《Java 本地接口规范Word格式.docx》由会员分享,可在线阅读,更多相关《Java 本地接口规范Word格式.docx(84页珍藏版)》请在冰点文库上搜索。

Java 本地接口规范Word格式.docx

接口函数表

版本信息

GetVersion

类操作

DefineClass

FindClass

GetSuperclass

IsAssignableFrom

异常

Throw

ThrowNew

ExceptionOccurred

ExceptionDescribe

ExceptionClear

FatalError

全局及局部引用

NewGlobalRef

DeleteGlobalRef

DeleteLocalRef

对象操作

AllocObject

 

GetObjectClass

IsInstanceOf

IsSameObject

访问对象的域

GetFieldID

Get<

type>

Field例程

Set<

调用实例方法

GetMethodID

Call<

Method

CallNonvirtual<

访问静态域

GetStaticFieldID

GetStatic<

SetStatic<

调用静态方法

GetStaticMethodID

CallStatic<

字符串操作

NewString

GetStringLength

GetStringChars

ReleaseStringChars

NewStringUTF

GetStringUTFLength

GetStringUTFChars

ReleaseStringUTFChars

数组操作

GetArrayLength

NewObjectArray

GetObjectArrayElement

SetObjectArrayElement

New<

PrimitiveType>

Array例程

ArrayElements例程

Release<

ArrayRegion例程

注册本地方法

RegisterNatives

UnregisterNatives

监视程序操作

MonitorEnter

MonitorExit

Java虚拟机接口

GetJavaVM

5.调用API

概述

创建虚拟机

连接虚拟机

卸载虚拟机

初始化结构

调用API函数

JNI_GetDefaultJavaVMInitArgs

JNI_GetCreatedJavaVMs

JNI_CreateJavaVM

DestroyJavaVM

AttachCurrentThread

DetachCurrentThread

1-简介

本章介绍Java本地接口(JavaNativeInterface,JNI)。

JNI是本地编程接口。

它使得在Java虚拟机(VM)内部运行的Java代码能够与用其它编程语言(如C、C++和汇编语言)编写的应用程序和库进行互操作。

JNI最重要的好处是它没有对底层Java虚拟机的实现施加任何限制。

因此,Java虚拟机厂商可以在不影响虚拟机其它部分的情况下添加对JNI的支持。

程序员只需编写一种版本的本地应用程序或库,就能够与所有支持JNI的Java虚拟机协同工作。

本章论及以下主题:

∙Java本地接口概述

∙背景

∙目标

∙Java本地接口方法

∙利用JNI编程

∙JDK1.1.2中的变化

尽管可以完全用Java编写应用程序,但是有时单独用Java不能满足应用程序的需要。

程序员使用JNI来编写Java本地方法,可以处理那些不能完全用Java编写应用程序的情况。

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

∙标准Java类库不支持与平台相关的应用程序所需的功能。

∙已经拥有了一个用另一种语言编写的库,而又希望通过JNI使Java代码能够访问该库。

∙想用低级语言(如汇编语言)实现一小段时限代码。

通过用JNI编程,可以将本地方法用于:

∙创建、检查及更新Java对象(包括数组和字符串)。

∙调用Java方法。

∙捕捉和抛出异常。

∙加载类和获得类信息。

∙执行运行时类型检查。

也可以与调用API一起使用JNI,以允许任意本地应用程序嵌入到Java虚拟机中。

这样使得程序员能够轻易地让已有应用程序支持Java,而不必与虚拟机源代码相链接。

目前,不同厂商的虚拟机提供了不同的本地方法接口。

这些不同的接口使程序员不得不在给定平台上编写、维护和分发多种版本的本地方法库。

下面简要分析一下部分已有本地方法接口,例如:

∙JDK1.0本地方法接口

∙Netscape的Java运行时接口

∙Microsoft的原始本地接口和Java/COM接口

JDK1.0附带有本地方法接口。

遗憾的是,有两点原因使得该接口不适合于其它Java虚拟机。

第一,平台相关代码将Java对象中的域作为C结构的成员来进行访问。

但是,Java语言规范没有规定在内存中对象是如何布局的。

如果Java虚拟机在内存中布局对象的方式有所不同,程序员就不得不重新编译本地方法库。

第二,JDK1.0的本地方法接口依赖于保守的垃圾收集器。

例如,无限制地使用unhand宏使得有必要以保守方式扫描本地堆栈。

Netscape建议使用Java运行时接口(JRI),它是Java虚拟机所提供服务的通用接口。

JRI的设计融入了可移植性---它几乎没有对底层Java虚拟机的实现细节作任何假设。

JRI提出了各种各样的问题,包括本地方法、调试、反射、嵌入(调用)等等。

MicrosoftJava虚拟机支持两种本地方法接口。

在低一级,它提供了高效的原始本地接口(RNI)。

RNI提供了与JDK本地方法接口有高度源代码级的向后兼容性,尽管它们之间还有一个主要区别,即平台相关代码必须用RNI函数来与垃圾收集器进行显式的交互,而不是依赖于保守的垃圾收集。

在高一级,Microsoft的Java/COM接口为Java虚拟机提供了与语言无关的标准二进制接口。

Java代码可以象使用Java对象一样来使用COM对象。

Java类也可以作为COM类显示给系统的其余部分。

我们认为统一的,经过细致考虑的标准接口能够向每个用户提供以下好处:

∙每个虚拟机厂商都可以支持更多的平台相关代码。

∙工具构造器不必维护不同的本地方法接口。

∙应用程序设计人员可以只编写一种版本的平台相关代码就能够在不同的虚拟机上运行。

获得标准本地方法接口的最佳途径是联合所有对Java虚拟机有兴趣的当事方。

因此,我们在Java获得许可方之间组织了一系列研讨会,对设计统一的本地方法接口进行了讨论。

从研讨会可以明确地看出标准本地方法接口必须满足以下要求:

∙二进制兼容性-主要的目标是在给定平台上的所有Java虚拟机实现之间实现本地方法库的二进制兼容性。

对于给定平台,程序员只需要维护一种版本的本地方法库。

∙效率-若要支持时限代码,本地方法接口必须增加一点系统开销。

所有已知的用于确保虚拟机无关性(因而具有二进制兼容性)的技术都会占用一定的系统开销。

我们必须在效率与虚拟机无关性之间进行某种折衷。

∙功能-接口必须显示足够的Java虚拟机内部情况以使本地方法能够完成有用的任务。

我们希望采用一种已有的方法作为标准接口,因为这样程序员(程序员不得不学习在不同虚拟机中的多种接口)的工作负担最轻。

遗憾的是,已有解决方案中没有任何方案能够完全地满足我们的目标。

Netscape的JRI最接近于我们所设想的可移植本地方法接口,因而我们采用它作为设计起点。

熟悉JRI的读者将会注意到在API命名规则、方法和域ID的使用、局部和全局引用的使用,等等中的相似点。

虽然我们进行了最大的努力,但是JNI并不具有对JRI的二进制兼容性,不过虚拟机既可以支持JRI,又可以支持JNI。

Microsoft的RNI是对JDK1.0的改进,因为它可以解决使用非保守的垃圾收集器的本地方法的问题。

然而,RNI不适合用作与虚拟机无关的本地方法接口。

与JDK类似,RNI本地方法将Java对象作为C结构来访问。

这将导致两个问题:

∙RNI将内部Java对象的布局暴露给了平台相关代码。

∙将Java对象作为C结构直接进行访问使得不可能有效地加入“写屏障”,写屏障是高级的垃圾收集算法所必需的。

作为二进制标准,COM确保了不同虚拟机之间的完全二进制兼容性。

调用COM方法只要求间接调用,而这几乎不会占用系统开销。

另外,COM对象对动态链接库解决版本问题的方式也有很大的改进。

然而,有几个因素阻碍了将COM用作标准Java本地方法接口:

∙第一,Java/COM接口缺少某些必需功能,例如访问私有域和抛出普通异常。

∙第二,Java/COM接口自动为Java对象提供标准的IUnknown和IDispatchCOM接口,因而平台相关代码能够访问公有方法和域。

遗憾的是,IDispatch接口不能处理重载的Java方法,而且在匹配方法名称时不区别大小写。

另外,通过IDispatch接口暴露的所有Java方法被打包在一起来执行动态类型检查和强制转换。

这是因为IDispatch接口的设计只考虑到了弱类型的语言(例如Basic)。

∙第三,COM允许软件组件(包括完全成熟的应用程序)一起工作,而不是处理单个低层函数。

我们认为将所有Java类或低层本地方法都当作软件组件是不恰当的。

∙第四,在UNIX平台上由于缺少对COM的支持,所以阻碍了直接采用COM。

虽然我们没有将Java对象作为COM对象暴露给平台相关代码,但是JNI接口自身与COM具有二进制兼容性。

我们采用与COM一样的跳转表和调用约定。

这意味着,一旦具有对COM的跨平台支持,JNI就能成为Java虚拟机的COM接口。

我们认为JNI不应该是给定Java虚拟机所支持的唯一的本地方法接口。

标准接口的好处在于程序员可以将自己的平台相关代码库加载到不同的Java虚拟机上。

在某些情况下,程序员可能不得不使用低层且与虚拟机有关的接口来获得较高的效率。

但在其它情况下,程序员可能使用高层接口来建立软件组件。

实际上,我们希望随着Java环境和组件软件技术发展得越来越成熟,本地方法将变得越来越不重要。

本地方法程序设计人员应开始利用JNI进行编程。

利用JNI编程隔离了一些未知条件,例如终端用户可能正在运行的厂商的虚拟机。

遵守JNI标准是本地库能在给定Java虚拟机上运行的最好保证。

例如,虽然JDK1.1将继续支持JDK1.0中所实现的旧式的本地方法接口,但是可以肯定的是JDK的未来版本将停止支持旧式的本地方法接口。

依赖于旧式接口的本地方法将不得不重新编写。

如果您正在实现Java虚拟机,则应该实现JNI。

我们(Javasoft和获得许可方)尽力确保JNI不会占用虚拟机实现的系统开销或施加任何限制,包括对象表示,垃圾收集机制等。

如果您遇到了我们可能忽视了的问题,请告知我们。

为了更好地支持Java运行时环境(JRE),在JDK1.1.2中对调用API在几个方面作了扩展。

这些变化没有破坏任何已有代码,JNI本地方法接口也没有改变。

∙JDK1_1InitArgs结构中的reserved0域已被重新命名为version。

JDK1_1InitArgs结构保存JNI_CreateJavaVM的初始化参数。

JNI_GetDefaultJavaVMInitArgs和JNI_CreateJavaVM的调用者必须将版本域设置为0x00010001。

JNI_GetDefaultJavaVMInitArgs被更改为返回jint,用于表示是否支持所请求的版本。

∙JDK1_1InitArgs结构中的reserved1域已被重新命名为properties。

这是一个NULL-终结的字符串数组。

每个字符串具有以下格式:

name=value

表示系统属性(该功能对应于Java命令行中的-D选项)。

∙在JDK1.1.1中,调用DestroyJavaVM的线程必须是虚拟机中的唯一用户线程。

JDK1.1.2放松了这一限制。

如果调用DestroyJavaVM时有多个用户线程,则虚拟机将等待直到当前线程成为唯一的用户线程,然后销毁自己。

2-设计概述

本章着重讨论JNI中的主要设计问题,其中的大部分问题都与本地方法有关。

调用API的设计将在第5章“调用API”中讨论。

平台相关代码是通过调用JNI函数来访问Java虚拟机功能的。

JNI函数可通过接口指针来获得。

接口指针是指针的指针,它指向一个指针数组,而指针数组中的每个元素又指向一个接口函数。

每个接口函数都处在数组的某个预定偏移量中。

图2-1说明了接口指针的组织结构。

图2-1接口指针

JNI接口的组织类似于C++虚拟函数表或COM接口。

使用接口表而不使用硬性编入的函数表的好处是使JNI名字空间与平台相关代码分开。

虚拟机可以很容易地提供多个版本的JNI函数表。

例如,虚拟机可支持以下两个JNI函数表:

∙一个表对非法参数进行全面检查,适用于调试程序;

∙另一个表只进行JNI规范所要求的最小程度的检查,因此效率较高。

JNI接口指针只在当前线程中有效。

因此,本地方法不能将接口指针从一个线程传递到另一个线程中。

实现JNI的虚拟机可将本地线程的数据分配和储存在JNI接口指针所指向的区域中。

本地方法将JNI接口指针当作参数来接受。

虚拟机在从相同的Java线程中对本地方法进行多次调用时,保证传递给该本地方法的接口指针是相同的。

但是,一个本地方法可被不同的Java线程所调用,因此可以接受不同的JNI接口指针。

对本地方法的加载通过System.loadLibrary方法实现。

下例中,类初始化方法加载了一个与平台有关的本地库,在该本地库中给出了本地方法f的定义:

packagepkg;

classCls{

nativedoublef(inti,Strings);

static{

System.loadLibrary("

pkg_Cls"

);

}

System.loadLibrary的参数是程序员任意选取的库名。

系统按照标准的但与平台有关的处理方法将该库名转换为本地库名。

例如,Solaris系统将名称pkg_Cls转换为libpkg_Cls.so,而Win32系统将相同的名称pkg_Cls转换为pkg_Cls.dll。

程序员可用单个库来存放任意数量的类所需的所有本地方法,只要这些类将被相同的类加载器所加载。

虚拟机在其内部为每个类加载器保护其所加载的本地库清单。

提供者应该尽量选择能够避免名称冲突的本地库名。

如果底层操作系统不支持动态链接,则必须事先将所有的本地方法链接到虚拟机上。

这种情况下,虚拟机实际上不需要加载库即可完成System.loadLibrary调用。

程序员还可调用JNI函数RegisterNatives()来注册与类关联的本地方法。

在与静态链接的函数一起使用时,RegisterNatives()函数将特别有用。

动态链接程序是根据项的名称来解析各项的。

本地方法名由以下几部分串接而成:

∙前缀Java_

∙mangled全限定的类名

∙下划线(“_”)分隔符

∙mangled方法名

∙对于重载的本地方法,加上两个下划线(“__”),后跟mangled参数签名

虚拟机将为本地库中的方法查找匹配的方法名。

它首先查找短名(没有参数签名的名称),然后再查找带参数签名的长名称。

只有当某个本地方法被另一个本地方法重载时程序员才有必要使用长名。

但如果本地方法的名称与非本地方法的名称相同,则不会有问题。

因为非本地方法(Java方法)并不放在本地库中。

下例中,不必用长名来链接本地方法g,因为另一个方法g不是本地方法,因而它并不在本地库中。

classCls1{

intg(inti);

nativeintg(doubled);

我们采取简单的名字搅乱方案,以保证所有的Unicode字符都能被转换为有效的C函数名。

我们用下划线(“_”)字符来代替全限定的类名中的斜杠(“/”)。

由于名称或类型描述符从来不会以数字打头,我们用_0、...、_9来代替转义字符序列,如表2-1所示:

表2-1Unicode字符转换

转义字符序列

表示

_0XXXX

Unicode字符XXXX。

_1

字符“_”

_2

签名中的字符“;

_3

签名中的字符“[”

本地方法和接口API都要遵守给定平台上的库调用标准约定。

例如,UNIX系统使用C调用约定,而Win32系统使用__stdcall。

JNI接口指针是本地方法的第一个参数。

其类型是JNIEnv。

第二个参数随本地方法是静态还是非静态而有所不同。

非静态本地方法的第二个参数是对对象的引用,而静态本地方法的第二个参数是对其Java类的引用。

其余的参数对应于通常Java方法的参数。

本地方法调用利用返回值将结果传回调用程序中。

第3章“JNI的类型和数据结构”将描述Java类型和C类型之间的映射。

代码示例2-1说明了如何用C函数来实现本地方法f。

对本地方法f的声明如下:

...

具有长mangled名称Java_pkg_Cls_f_ILjava_lang_String_2的C函数实现本地方法f:

代码示例2-1:

用C实现本地方法

jdoubleJava_pkg_Cls_f__ILjava_lang_String_2(

JNIEnv*env,/*接口指针*/

jobjectobj,/*“this”指针*/

jinti,/*第一个参数*/

jstrings)/*第二个参数*/

{

/*取得Java字符串的C版本*/

constchar*str=(*env)->

GetStringUTFChars(env,s,0);

/*处理该字符串*/

/*至此完成对str的处理*/

(*env)->

ReleaseStringUTFChars(env,s,str);

return...

注意,我们总是用接口指针env来操作Java对象。

可用C++将此代码写得稍微简洁一些,如代码示例2-2所示:

代码示例2-2:

用C++实现本地方法

extern"

C"

/*指定C调用约定*/

constchar*str=env->

GetStringUTFChars(s,0);

env->

ReleaseStringUTFChars(s,str);

使用C++后,源代码变得更为直接,且接口指针参数消失。

但是,C++的内在机制与C的完全一样。

在C++中,JNI函数被定义为内联成员函数,它们将扩展为相应的C对应函数。

基本类型(如整型、字符型等)在Java和平台相关代码之间直接进行复制。

而Java对象由引用来传递。

虚拟机必须跟踪传到平台相关代码中的对象,以使这些对象不会被垃圾收集器释放。

反之,平台相关代码必须能用某种方式通知虚拟机它不再需要那些对象,同时,垃圾收集器必须能够移走被平台相关代码引用过的对象。

JNI将平台相关代码使用的对象引用分成两类:

局部引用和全局引用。

局部引用在本地方法调用期间有效,并在本地方法返回后被自动释放掉。

全局引用将一直有效,直到被显式释放。

对象是被作为局部引用传递给本地方法的,由JNI函数返回的所有Java对象也都是局部引用。

JNI允许程序员从局部引用创建全局引用。

要求Java对象的JNI函数既可接受全局引用也可接受局部引用。

本地方法将局部引用或全局引用作为结果返回。

大多数情况下,程序员应该依靠虚拟机在本地方法返回后释放所有局部引用。

但是,有时程序员必须显式释放某个局部引用。

例如,考虑以下的情形:

∙本地方法要访问一个大型Java对象,于是创建了对该Java对象的局部引用。

然后,本地方法要在返回调用程序之前执行其它计算。

对这个大型Java对象的局部引用将防止该对象被当作垃圾收集

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2