美文网首页
JNI完全指南(五)——字符串与数组

JNI完全指南(五)——字符串与数组

作者: 798fe2ac8685 | 来源:发表于2016-11-15 15:36 被阅读1885次

    标签(空格分隔): JNI完全指南

    版本:1
    作者:陈小默
    声明:禁止商业,禁止转载
    

    发布于:作业部落简书CSDN博客


    上一篇:JNI完全指南(四)——对象操作


    [toc]


    五、字符串与数组

    5.1 Java字符串

    5.1.1 新建Java字符串

    在JNI中,如果需要使用一个Java字符串,可以采用如下方式新建String对象。

    jstring NewString(JNIEnv *env, const jchar *unicodeChars,
    jsize len);

    • unicodeChars:一个指向Unicode编码的字符数组的指针。
    • len:unicodeChars的长度
    • return:Java字符串对象

    存在异常

    • OutOfMemoryError

    5.1.2 获取Java字符串长度

    通过以下方法我们能够获取到Java字符串的长度

    jsize GetStringLength(JNIEnv *env, jstring string);

    • string:Java字符串对象
    • return:字符串长度

    5.1.3 从Java字符串获取字符数组

    我们可以通过以下方法从Java字符串获取字符数组,当使用完毕后,我们需要调用ReleaseStringChars进行释放。

    const jchar * GetStringChars(JNIEnv *env, jstring string,
    jboolean *isCopy);

    • isCopy:注意,这个参数很重要,这是一个指向Java布尔类型的指针。函数返回之后应当检查这个参数的值,如果值为JNI_TRUE表示返回的字符是Java字符串的拷贝,我们可以对其中的值进行任意修改。如果返回值为JNI_FALSE,表示这个字符指针指向原始Java字符串的内存,这时候对字符数组的任何修改都将会原始字符串的内容。如果你不关系字符数组的来源,或者说你的操作不会对字符数组进行任何修改,可以传入NULL。
    • return:指向字节数组的指针

    5.1.4 释放从Java字符串中获取的字符数组

    void ReleaseStringChars(JNIEnv *env, jstring string,
    const jchar *chars);

    • string:Java字符串对象。
    • chars:字符数组。

    5.1.5 新建UTF-8编码字符串

    jstring NewStringUTF(JNIEnv *env, const char *bytes);

    • bytes:UTF-8编码的字节数组。
    • return:UTF-8编码的Java字符串对象

    5.1.6 获取UTF-8字符串的长度

    参考2.11.2
    jsize GetStringUTFLength(JNIEnv *env, jstring string);

    5.1.7 获取UTF-8编码的Java字符串的

    参考2.11.3

    const char * GetStringUTFChars(JNIEnv *env, jstring string,
    jboolean *isCopy);

    5.1.8 释放从UTF-8字符串中获取的字符数组

    参考2.11.4

    void ReleaseStringUTFChars(JNIEnv *env, jstring string,
    const char *utf);

    5.1.9 从Java字符串中截取一段字符

    如果我们想要从字符串中获取其中的一段内容,可以采用如下方式:

    void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);

    • str:Java字符串对象。
    • start:起始位置。
    • len:截取长度。
    • buf:保存截取结果的缓冲区。

    存在异常

    • StringIndexOutOfBoundsException

    5.1.10 从UTF-8字符串中截取一段字符

    参考2.11.9

    void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);

    5.1.11 直接字符串指针

    当我们需要获取字符数组时,使用上面2.11.3和2.11.7的方法都有可能或得到原始字符串的拷贝,很明显这对运行效率有些影响。如果我们能够获得原始字符串的直接指针,就可以极大地优化运行效率。于是JNI提供了Get/ReleaseStringCritical两个函数来操作原始字符串的直接指针。但是对直接指针的操作有着极其严格的限制。这两个函数之间不能存在任何会让线程阻塞的操作。
    这两个函数原型如下:

    const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);

    void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);


    5.2 Java数组

    5.2.1 获取数组长度

    jsize GetArrayLength(JNIEnv *env, jarray array);

    5.2.2 新建对象数组

    使用如下方法可以创建一个对象数组。

    jobjectArray NewObjectArray(JNIEnv *env, jsize length,
    jclass elementClass, jobject initialElement);

    • length:数组的长度。
    • elementClass:数组中的对象类型。
    • initialElement:数组中的每个元素都会使用这个值进行初始化,可以为NULL。
    • return:对象数组,创建失败返回NULL

    存在异常

    • OutOfMemoryError

    5.2.3 获取对象数组元素

    在JNI中获取对象数组元素需要使用下列函数

    jobject GetObjectArrayElement(JNIEnv *env,
    jobjectArray array, jsize index);

    • array:对象数组
    • index:位置索引

    存在异常

    • ArrayIndexOutOfBoundsException

    5.2.4 设置对象数组元素

    void SetObjectArrayElement(JNIEnv *env, jobjectArray array,
    jsize index, jobject value);

    存在异常

    • ArrayIndexOutOfBoundsException
    • ArrayStoreException:传入的值与数组类型不一致

    5.2.5 基本数据类型数组

    新建基本数据类型数组的函数与2.12.2类似,函数原型为

    ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);

    具体函数名与返回值类型的关系如下表所示:

    函数名 返回数组类型
    NewBooleanArray jbooleanArray
    NewByteArray jbyteArray
    NewCharArray jcharArray
    NewShortArray jshortArray
    NewIntArray jintArray
    NewLongArray jlongArray
    NewFloatArray jfloatArray
    NewDoubleArray jdoubleArray

    获取基本数据类型数组元素的函数原型为

    NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,
    ArrayType array, jboolean *isCopy);

    • isCopy:参考2.11.3

    具体函数名与返回类型的关系如下表所示:

    函数名 参数数组类型 返回值类型
    GetBooleanArrayElements jbooleanArray jboolean
    GetByteArrayElements jbyteArray jbyte
    GetCharArrayElements jcharArray jchar
    GetShortArrayElements jshortArray jshort
    GetIntArrayElements jintArray jint
    GetLongArrayElements jlongArray jlong
    GetFloatArrayElements jfloatArray jfloat
    GetDoubleArrayElements jdoubleArray jdouble

    释放基本数据类型数组

    void Release<PrimitiveType>ArrayElements(JNIEnv *env,
    ArrayType array, NativeType *elems, jint mode);

    mode 行为
    0 copy back the content and free the elems buffer
    JNI_COMMIT copy back the content but do not free the elems buffer
    JNI_ABORT free the buffer without copying back the possible changes
    函数名 数组类型 元素类型
    ReleaseBooleanArrayElements jbooleanArray jboolean
    ReleaseByteArrayElements jbyteArray jbyte
    ReleaseCharArrayElements jcharArray jchar
    ReleaseShortArrayElements jshortArray jshort
    ReleaseIntArrayElements jintArray jint
    ReleaseLongArrayElements jlongArray jlong
    ReleaseFloatArrayElements jfloatArray jfloat
    ReleaseDoubleArrayElements jdoubleArray jdouble

    5.2.6 截取数组

    详情参考2.11.9,函数原型如下:

    void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
    jsize start, jsize len, NativeType *buf);

    函数名 数组类型 数据类型
    GetBooleanArrayRegion jbooleanArray jboolean
    GetByteArrayRegion jbyteArray jbyte
    GetCharArrayRegion jcharArray jchar
    GetShortArrayRegion jshortArray jhort
    GetIntArrayRegion jintArray jint
    GetLongArrayRegion jlongArray jlong
    GetFloatArrayRegion jfloatArray jloat
    GetDoubleArrayRegion jdoubleArray jdouble

    5.2.7 范围设置数组

    我们可以通过如下方法给数组的部分赋值

    void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array,
    jsize start, jsize len, const NativeType *buf);

    函数名 数据类型 参数类型
    SetBooleanArrayRegion jbooleanArray jboolean
    SetByteArrayRegion jbyteArray jbyte
    SetCharArrayRegion jcharArray jchar
    SetShortArrayRegion jshortArray jshort
    SetIntArrayRegion jintArray jint
    SetLongArrayRegion jlongArray jlong
    SetFloatArrayRegion jfloatArray jfloat
    SetDoubleArrayRegion jdoubleArray jdouble

    5.2.8 操作基本数据类型数组的直接指针

    在某些情况下,我们需要原始数据指针来进行一些操作。调用GetPrimitiveArrayCritical后,我们可以获得一个指向原始数据的指针,但是在调用ReleasePrimitiveArrayCritical函数之前,我们要保证不能进行任何可能会导致线程阻塞的操作。由于GC的运行会打断线程,所以在此期间任何调用GC的线程都会被阻塞。

    void * GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy);
    void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode);

    jint len = (*env)->GetArrayLength(env, arr1);
      jbyte *a1 = (*env)->GetPrimitiveArrayCritical(env, arr1, 0);
      jbyte *a2 = (*env)->GetPrimitiveArrayCritical(env, arr2, 0);
      /* We need to check in case the VM tried to make a copy. */
      if (a1 == NULL || a2 == NULL) {
        ... /* out of memory exception thrown */
      }
      memcpy(a1, a2, len);
      (*env)->ReleasePrimitiveArrayCritical(env, arr2, a2, 0);
      (*env)->ReleasePrimitiveArrayCritical(env, arr1, a1, 0);
    

    下一篇:JNI完全指南(六)——本地方法


    [1]ORACLE guides for JNI——Chapter 4: JNI Functions

    相关文章

      网友评论

          本文标题:JNI完全指南(五)——字符串与数组

          本文链接:https://www.haomeiwen.com/subject/cmflpttx.html