JNI编程参考备忘----基本类型

来源:互联网 发布:网络经常听的dj 编辑:程序博客网 时间:2024/05/14 10:44

Java编程中,本地方法的声明一般如下:

private native String getLine(String prompt);

跟其他普通的Java类的方法相比,只有声明,没有方法体,且必须带一个native修饰符。另外,在类中,通过静态代码初始化的方法,调用System.loadLibrary(...)方法,加载本地方法的实现——JNI库,如下为Java本地方法使用的一个范例:

public class Prompt implements TestCase{    //native method that prints a prompt and reads a line    private native String getLine(String prompt);        static {        String path = System.getProperty("java.library.path");        System.loadLibrary("Prompt");    }    @Override    public void doTest() {       String input  = this.getLine("Please input something and enter return");       System.out.println("User Typed: " + input);    }    }

如上所示,系统将加载libPrompt.so库。在JNI本地实现代码中,对应的方法声明如下:

JNIEXPORT jstring JNICALL Java_com_fyj_test_Prompt_getLine

  (JNIEnv *, jobject, jstring);

第一个参数JNIEnv是一个接口指针,它指向了一个位置,该位置是一个指针数组,它包含了许多JNI函数的指针。根据本地方法的声明方式,如果声明了类的静态方法,则第二个参数是该类的一个引用,否则这个参数就是对该类实例的一个引用,相当于this指针。

 

基本类型

Java中,有两种类型,一种是初始类型int,float,以及char,还有一种是引用类型如类,实例以及数组。JNI对这两种类型的处理不一样。对于初始类型,与C/C++编程语言类型的映射很简单,如int对应jint, float对应jfloat等等。而对于引用类型,JNI则当作不透明引用,即C的指针类型,它们指向Java虚拟机的内部数据结构。本地方法必须通过合适的JNI函数来操控它们。例如,对于java.lang.String类,它对应的C/C++类型为jstring。本地代码要访问这个字符串的内容必须通过调用JNI函数如GetStringUTFChars

字符串访问

JNI层本地代码对应的数据类型为jstring,但是,不能直接当作普通的C字符串,必须使用合适的JNI函数来将jstring对象转换为C/C++字符串。JNI支持UnicodeUTF-8字符串与jstring对象的双向转换。示例代码如下:

JNIEXPORT jstring JNICALL Java_com_fyj_test_Prompt_getLine  (JNIEnv *env, jobject obj, jstring prompt){#if 0    char buf[128];    const jbyte *str;    str = (*env)->GetStringUTFChars(env, prompt, NULL);    if (str == NULL) {        return NULL; /* OutOfMemoryError already thrown */    }    printf("%s", str);    (*env)->ReleaseStringUTFChars(env, prompt, str);    /* We assume here that the user does not type more than    * 127 characters */    scanf("%s", buf);    return (*env)->NewStringUTF(env, buf);#endif    /* assume the prompt string and user input has less than 128    characters */    char outbuf[128], inbuf[128];    int len = (*env)->GetStringLength(env, prompt);    (*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf);    printf("%s", outbuf);    scanf("%s", inbuf);    return (*env)->NewStringUTF(env, inbuf);}

字符串相关的JNI函数如下所示:

 

JNI Function

Description

Since

GetStringChars

ReleaseStringChars

Obtains or releases a pointer to the contents of a string in Unicode format. May return a copy of the string.

JDK1.1

GetStringUTFChars

ReleaseStringUTFChars

Obtains or releases a pointer to the contents of a string in UTF-8 format. May return a copy of the string.

JDK1.1

GetStringLength

Returns the number of Unicode characters in the string.

JDK1.1

GetStringUTFLength

Returns the number of bytes needed (not including the trailing 0) to represent a string in the UTF-8 format.

JDK1.1

NewString

Creates a java.lang.String instance that contains the same sequence of characters as the given Unicode C string.

JDK1.1

NewStringUTF

Creates a java.lang.String instance that contains the same sequence of characters as the given UTF-8 encoded C string.

JDK1.1

GetStringCritical

ReleaseStringCritical

Obtains a pointer to the contents of a string in Unicode format. May return a copy of the string. Native code must not block between a pair of Get/ReleaseStringCritical calls.

JDK1.1

GetStringRegion

SetStringRegion

Copies the contents of a string to or from a preallocated C buffer in the Unicode format.

Java 2

SDK1.2

GetStringUTFRegion

SetStringUTFRegion

Copies the content of a string to or from a preallocated C buffer in the UTF-8 format.

Java 2

SDK 1.2


初始类型数组访问

初始数据类型的数组访问与对象类型的数组访问又有不同。访问初始类型的数据与访问字符串一样,也需要使用JNI函数进行转换。

如下代码所示:

JNIEXPORT jint JNICALL Java_com_fyj_test_IntArray_sumArray  (JNIEnv *env, jobject obj, jintArray arr){#if 0    jint buf[100];    jint i, sum = 0;    (*env)->GetIntArrayRegion(env, arr, 0, 100, buf);    for (i = 0; i < 100; i++) {        sum += buf[i];    }    return sum;#endif    jint *carr;    jint i, sum = 0;    carr = (*env)->GetIntArrayElements(env, arr, NULL);    if (carr == NULL) {        return 0; /* exception occurred */    }    for (i=0; i<100; i++) {     sum += carr[i];    }    (*env)->ReleaseIntArrayElements(env, arr, carr, 0);    return sum;}

相关的JNI函数如下:

 

JNI Function

Description

Since

Get<Type>ArrayRegion

Set<Type>ArrayRegion

Copies the contents of primitive arrays to or from a pre-allocated C buffer.

JDK 1.1

Get<Type>ArrayElements

Release<Type>ArrayElements

Obtains a pointer to the contents of a primitive array.

May return a copy of the array.

JDK 1.1

GetArrayLength

Returns the number of elements in the array.

JDK 1.1

New<Type>Array

Creates an array with the given length.

JDK 1.1

GetPrimitiveArrayCritical

ReleasePrimitiveArrayCritica

Obtains or releases a pointer to the contents of a primitive array. May disable garbage collection, or return a copy of the array.

Java 2

SDK 1.2

 

对象类型数组访问

访问对象类型数组需要使用一组不同的JNI函数:

GetObjectArrayElement:返回某个下标处的元素。

SetObjectArrayElement:设置某个下标处的元素。

不同于初始类型数组,你不能一次获取整个对象元素或复制多个对象元素。

由于字符串和数组也属于引用类型,所以可以使用上述函数访问字符串数组或数组的数组。代码示例如下:

JNIEXPORT jobjectArray JNICALL Java_com_fyj_test_ObjectArrayTest_initInt2DArray  (JNIEnv *env, jclass cls, jint size){    jobjectArray result;    int i;    jclass intArrCls = (*env)->FindClass(env, "[I");    if (intArrCls == NULL) {        return NULL; /* exception thrown */    }    result = (*env)->NewObjectArray(env, size, intArrCls,    NULL);    if (result == NULL) {        return NULL; /* out of memory error thrown */    }    for (i = 0; i < size; i++) {        jint tmp[256]; /* make sure it is large enough! */        int j;        jintArray iarr = (*env)->NewIntArray(env, size);        if (iarr == NULL) {            return NULL; /* out of memory error thrown */        }        for (j = 0; j < size; j++) {            tmp[j] = i + j;        }        (*env)->SetIntArrayRegion(env, iarr, 0, size, tmp);        (*env)->SetObjectArrayElement(env, result, i, iarr);        (*env)->DeleteLocalRef(env, iarr);    }    return result;}


0 0
原创粉丝点击