oracle jni getintarrayelements,JNI ------ 入门

从Java 1.1开始,Java Native Interface

(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,

但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。让我们看一些使用JNI的简单例子吧。

使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,

与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下。

开始:

如果你习惯了使用JNI,你就不会觉得它难了。既然本地方法是由其他语言实现的,它们在Java中没有函数体。但是,所有本地代码必须用本地关

键词声明,成为Java类的成员。清单A演示了一个简单的类,它申明了一个本地的(native),静态的(static)方法:sum。

写完了你的Java类,接下来就要写本地代码。本地方法符号提供一个满足约定的头文件,使用Java工具可以很容易地创建它而不用手动去创建。

你对Java的class文件使用javah命令,就会为你生成一个对应的C/C++头文件。清单B就是为清单A的Test1类创建的头文件。注意:它创建了一个

C/C++函数:Java_Test1_sum。

执行本地方法:

一旦你有了这个头文件,你就需要写头文件对应的本地方法,就像我在清单C做的那样。

注意:所有的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的,(我会在另一个章节中讨论)。第二个参数jclass的意义,

要看方法是不是静态的(static)或者实例(Instance)的。前者,jclass代表一个类对象的引用,而后者是被调用的方法所属对象的引用。最后的两个

jint参数表示了Java方法的 int参数。

返回值和参数类型根据等价约定映射到本地C/C++类型,如表A所示。有些类型,如清单B里面的两个jint参数,在本地代码中可直接使用,而其他类型

只有通过JNI调用操作。

表A

Java类型          本地类型             描述

+---------------+--------------------+--------------------------+

|boolean      |    jboolean        |    C/C++8位整型|

|byte         |    jbyte           |    C/C++带符号的8位整型|

|char         |    jchar           |    C/C++无符号的16位整型|

|short        |    jshort          |    C/C++带符号的16位整型|

|int          |    jint            |    C/C++带符号的32位整型|

|long         |    jlong           |    C/C++带符号的64位整型|

|float        |    jfloat          |    C/C++32位浮点型|

|double       |    jdouble         |    C/C++64位浮点型|

|  Object       |    jobject 有对应  |    任何Java对象,或者没  |

||                    |    有java 类型的对象|

|Class        |    jclass          |    Class对象|

|  String       |    jstring         |    字符串对象          |

+---------------+--------------------+--------------------------+

| Object[]      |    jobjectArray    |    任何对象的数组       |

| boolean[]     |    jbooleanArray   |    布尔型数组          |

| byte[]        |    jbyteArray      |    比特型数组          |

| char[]        |    jcharArray      |    字符型数组          |

| short[]       |    jshortArray     |    短整型数组          |

| int[]         |    jintArray       |    整型数组            |

| long[]        |    jlongArray      |    长整型数组            |

| float[]       |    jfloatArray     |    浮点型数组          |

| double[]      |    jdoubleArray    |    双浮点型数组          |

+---------------+--------------------+--------------------------+

※ JNI类型映射

最后一步是把本地代码编译成共享库(比如,UNIX的so文件,Windows的dll文件)。在Java中调用方法前,共享库须通过System.loadLibrary导入。

最常用的方式是在类的静态(static)初始化器里做这这个工作。

在本地代码中访问JNI我举的例子很简单,并不能满足演示怎样写JNI方法的目标。现在,让我们看一些高级的,通过JNIEnv结构使用非简单类型的例子。

JNI通过函数的形式提供了很多功能,供本地代码通过指向JNIEnv结构的指针调用;它作为第一个参数传递给每个本地方法。JNI函数的调用有下面

几种格式(这里,假设env是指向JNIEnv的指针):

//C 格式

(*env)-><jni function>( env, <parameters> )

//C++ 格式

env-><jni function>( < parameters> )

这篇文章中接下来的例子我将会用C++格式。

使用数组:

JNI通过JNIEnv提供的操作Java数组的功能。它提供了两个函数:一个是操作java的简单

型数组的,另一个是操作对象类型数组的。

因为速度的原因,简单类型的数组作为指向本地类型的指针暴露给本地代码。因此,它

们能作为常规的数组存取。这个指针是指向实际的Java数组或者Java数组的拷贝的指针。另

外,数组的布置保证匹配本地类型。

为了存取Java简单类型的数组,你就要要使用GetXXXArrayElements函数(见表B),XX

X代表了数组的类型。这个函数把Java数组看成参数,返回一个指向对应的本地类型的数组的

指针。

表B

函数                Java数组类型        本地类型

+--------------------------+---------------------+-----------------+

|GetBooleanArrayElements  |    jbooleanArray    |    jboolean|

|GetByteArrayElements     |    jbyteArray       |    jbyte|

|GetCharArrayElements     |    jcharArray       |    jchar|

|GetShortArrayElements    |    jshortArray      |    jshort|

|GetIntArrayElements      |    jintArray        |    jint|

|GetLongArrayElements     |    jlongArray       |    jlong|

|GetFloatArrayElements    |    jfloatArray      |    jfloat|

|GetDoubleArrayElements   |    jdoubleArray     |    jdouble|

JNI数组存取函数

当你对数组的存取完成后,要确保调用相应的ReleaseXXXArrayElements函数,参数是对应Java数组和 GetXXXArrayElements返回的指针。

如果必要的话,这个释放函数会复制你做的任何变化(这样它们就反射到java数组),然后释放所有相关的资源。

为了使用java对象的数组,你必须使用GetObjectArrayElement函数和SetObjectArrayElement函数,分别去get,set数组的元素。

GetArrayLength函数会返回数组的长度。

清单D包含了一个简单的类,它演示了本地代码如何使用Java数组。这个本地实现循环遍历一个整型(int)数组,返回这些元素的总和。

为简单起见,这个清单包含了java代码和本地实现。我已经省略了头文件,它可以很方便地通过javah得到。

在本地代码中访问JNI   使用对象

JNI 提供的另外一个功能是在本地代码中使用Java对象。通过使用合适的JNI函数,你可以创建Java对象,get、set 静态(static)和

实例(instance)的域,调用静态(static)和实例(instance)函数。JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。

表C列出了用以得到静态(static)和实例(instance)的域与方法的JNI函数。每个函数接受(作为参数)域或方法的类,它们的名称,符号和

它们对应返回的jfieldID或jmethodID。

表C

函数                  描述

+--------------------+---------------------------+

|GetFieldID        |    得到一个实例的域的ID|

|GetStaticFieldID  |    得到一个静态的域的ID|

|GetMethodID       |    得到一个实例的方法的ID|

|GetStaticMethodID |    得到一个静态方法的ID|

※域和方法的函数

如果你有了一个类的实例,它就可以通过方法GetObjectClass得到,或者如果你没有这个类的实例,可以通过FindClass得到。符号是从域的类型或者

方法的参数,返回值得到字符串,如表D所示。

表D

+------------+---------+

|Java 类型   |    符号 |

+------------+---------+

|boolean     |    Z   |

|byte        |    B   |

|char        |    C   |

|short       |    S    |

|int         |    I    |

|long        |    L    |

|float       |    F    |

|double      |    D    |

|void        |    V    |

|objects对象 |         |

+------------+---------+

Lfully-qualified-class-name;L类名

Arrays数组 [array-type [数组类型 methods方法 (argument-types)return-type(参数类型)返回类型

※确定域和方法的符号

一旦你有了类和方法或者域的ID,你就能把它保存下来以后使用,而没有必要重复去获取。

有几个分别访问域和方法的函数。实例的域可以使用对应域的GetXXXField的变体函数访问。GetStaticXXXField函数用于静态类型。

设置域的值,用SetXXXField 和SetStaticXXXField函数。表E包含了所有访问域的函数列表。

表E

+-------------+---------------------------+

|  Java类型   |    Method方法             |

+-------------+---------------------------+

|   boolean   |    GetBooleanField        |

|             |    GetStaticBooleanField  |

|             |    SetBooleanField        |

|             |    SetStaticBooleanField  |

+-------------+---------------------------+

|   byte      |    GetByteField           |

|             |    GetStaticByteField     |

|             |    SetByteField           |

|             |    SetStaticByteField   |

+-------------+---------------------------+

|   char      |    GetCharField           |

|             |    GetStaticCharField     |

|             |    SetCharField           |

|             |    SetStaticCharField   |

+-------------+---------------------------+

|   short     |    GetShortField          |

|             |    GetStaticShortField    |

|             |    SetShortField          |

|             |    SetStaticShortField   |

+-------------+---------------------------+

|    int      |    GetIntField,           |

|             |    GetStaticIntField,     |

|             |    SetIntField,           |

|             |    SetStaticIntField     |

+-------------+---------------------------+

|   long      |    GetLongField,          |

|             |    GetStaticLongField,    |

|             |    SetLongField,          |

|             |    SetStaticLongField    |

+-------------+---------------------------+

|   float     |    GetFloatField,         |

|             |    GetStaticFloatField,   |

|             |    SetFloatField,         |

|             |    SetStaticFloatField    |

+-------------+---------------------------+

| double     |    GetDoubleField,        |

|             |    GetStaticDoubleField,  |

|             |    SetDoubleField,        |

|             |    SetStaticDoubleField  |

+-------------+---------------------------+

|  object     |    GetObjectField,        |

|             |    GetStaticObjectField,  |

|             |    SetObjectField,        |

|             |    SetStaticObjectField   |

+-------------+---------------------------+

※访问域的函数

另外,方法的访问是由 CallXXXMethod 函数和 CallStaticXXXMethod函数完成的,XXX表明了方法的返回值类型。这些函数的变体允

许传递数组参数 (CallXXXMethodA and CallStaticXXXMethodA)或者传递一个可变大小的列表(CallXXXMethodV and CallStaticXXXMethodV)。

一个完整的列表

表F:一个完整的列表

返回类型    函数

+-------------+---------------------------+

|    boolean  |  CallBooleanMethod        |

|             |  CallBooleanMethodA       |

|             |  CallBooleanMethodV       |

|             |  CallStaticBooleanMethod  |

|             |  CallStaticBooleanMethodA |

|             |  CallStaticBooleanMethodV |

+-------------+---------------------------+

|    byte     |  CallByteMethod           |

|             |  CallByteMethodA          |

|             |  CallByteMethodV          |

|             |  CallStaticByteMethod     |

|             |  CallStaticByteMethodA    |

|             |  CallStaticByteMethodV    |

+-------------+---------------------------+

|    char     |  CallCharMethod           |

|             |  CallCharMethodA          |

|             |  CallCharMethodV          |

|             |  CallStaticCharMethod     |

|             |  CallStaticCharMethodA    |

|             |  CallStaticCharMethodV   |

+-------------+---------------------------+

|    short    |  CallShortMethod          |

|             |  CallShortMethodA         |

|             |  CallShortMethodV         |

|             |  CallStaticShortMethod    |

|             |  CallStaticShortMethodA   |

|             |  CallStaticShortMethodV   |

+-------------+---------------------------+

|    int      |  CallIntMethod            |

|             |  CallIntMethodA           |

|             |  CallIntMethodV           |

|             |  CallStaticIntMethod      |

|             |  CallStaticIntMethodA     |

|             |  CallStaticIntMethodV    |

+-------------+---------------------------+

|    long     |  CallLongMethod           |

|             |  CallLongMethodA          |

|             |  CallLongMethodV          |

|             |  CallStaticLongMethod     |

|             |  CallStaticLongMethodA    |

|             |  CallStaticLongMethodV   |

+-------------+---------------------------+

|    float    |  CallFloatMethod          |

|             |  CallFloatMethodA         |

|             |  CallFloatMethodV         |

|             |  CallStaticFloatMethod    |

|             |  CallStaticFloatMethodA   |

|             |  CallStaticFloatMethodV   |

+-------------+---------------------------+

|    double   |  CallDoubleMethod         |

|             |  CallDoubleMethodA        |

|             |  CallDoubleMethodV        |

|             |  CallStaticDoubleMethod   |

|             |  CallStaticDoubleMethodA  |

|             |  CallStaticDoubleMethodV |

+-------------+---------------------------+

| void        |  CallVoidMethod           |

|             |  CallVoidMethodA          |

|             |  CallVoidMethodV          |

|             |  CallStaticVoidMethod     |

|             |  CallStaticVoidMethodA    |

|             |  CallStaticVoidMethodV    |

+-------------+---------------------------+

| object      |  CallObjectMethod         |

|             |  CallObjectMethodA        |

|             |  CallObjectMethodV        |

|             |  CallStaticObjectMethod   |

|             |  CallStaticObjectMethodA  |

|             |  CallStaticObjectMethodV  |

+-------------+---------------------------+

当你关注java的扩展时,JNI是一个强大的工具,它不会严重降低可移植性。我这里只是接触它的表面,仅仅向你演示了JNI的能力和潜力。我鼓励你获取

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值