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

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值