跳转至

jni 接口说明

1 JNI中GetStringChars

  • JNI中GetStringChars函数中的isCopy
  • 定义: const char * GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)
    • isCopy :当函数执行完后,isCopy ==JNI_TRUE 表示得到的字符串是 java.lang.String 的拷贝;isCopy ==JNI_FALSE 表示得到的字符串是 java.lang.String 引用,本地代码决不能修改字符串的内容,否则JVM中的原始字符串也会被修改,这会打破JAVA语言中字符串不可变的规则
  • 注意:
    • 通常我们不关注 isCopy 的值,可以传NULL。
    • 在不再使用返回的字符串,需要调用 ReleaseStringUTFChars 进行释放。
  • 示例
JNIEXPORT jstring JNICALL Java_com_study_jnilearn_Sample_sayHello(JNIEnv *env, jclass cls, jstring j_str)
{
    const char *c_str = NULL;
    char buff[128] = {0};
    jboolean isCopy; // 返回JNI_TRUE表示原字符串的拷贝,返回JNI_FALSE表示返回原字符串的指针
    c_str = (*env)->GetStringUTFChars(env, j_str, &isCopy);
    printf("isCopy:%d\n", isCopy);
    if (c_str == NULL)
    {
        return NULL;
    }
    printf("C_str: %s \n", c_str);
    sprintf(buff, "hello %s", c_str);
    (*env)->ReleaseStringUTFChars(env, j_str, c_str);
    return (*env)->NewStringUTF(env, buff);
}

2 获取实例变量

  • 涉及接口:
    1. jclass GetObjectClass(JNIEnv *env, jobject obj); :从对象获取类名
    2. jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); :从对象中获取属性字段的id
    3. _NativeType_ _Get<type>Field_(JNIEnv *env, jobject obj, jfieldIfieldID) :根据对象和属性 id 获取相应的属性值
  • 不同类型获取值函数如下 | Get<type>Field Routine Name | Native Type | | --------------------------- | ----------- | | GetObjectField() | jobject | | GetBooleanField() | jboolean | | GetByteField() | jbyte | | GetCharField() | jchar | | GetShortField() | jshort | | GetIntField() | jint | | GetLongField() | jlong | | GetFloatField() | jfloat | | GetDoubleField() | jdouble |
  • 示例
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessInstanceField(JNIEnv *env, jclass cls, jobject obj)
{
    jclass clazz;
    jfieldID fid;
    jstring j_str;
    jstring j_newStr;
    const char *c_str = NULL;

    // 1.获取AccessField类的Class引用
    clazz = (*env)->GetObjectClass(env, obj);
    if (clazz == NULL)
    {
        return;
    }

    // 2. 获取AccessField类实例变量str的属性ID
    fid = (*env)->GetFieldID(env, clazz, "str", "Ljava/lang/String;");
    if (clazz == NULL)
    {
        return;
    }

    // 3. 获取实例变量str的值
    j_str = (jstring)(*env)->GetObjectField(env, obj, fid);

    // 4. 将unicode编码的java字符串转换成C风格字符串
    c_str = (*env)->GetStringUTFChars(env, j_str, NULL);
    if (c_str == NULL)
    {
        return;
    }
    printf("In C--->ClassField.str = %s\n", c_str);
    (*env)->ReleaseStringUTFChars(env, j_str, c_str);

    // 5. 修改实例变量str的值
    j_newStr = (*env)->NewStringUTF(env, "This is C String");
    if (j_newStr == NULL)
    {
        return;
    }

    (*env)->SetObjectField(env, obj, fid, j_newStr);

    // 6.删除局部引用
    (*env)->DeleteLocalRef(env, clazz);
    (*env)->DeleteLocalRef(env, j_str);
    (*env)->DeleteLocalRef(env, j_newStr);
}

3 获取静态变量

  • 涉及接口:
    • jclass FindClass(JNIEnv *env, const char *name); :通过类签名找到类
    • jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); :通过类、字段属性名、字段类型签名找到字段id
    • _NativeType_ _GetStatic<type>Field_ (JNIEnv *env, jclass clazz, jfieldID fieldID); :根据类和字段 id 获取相应的字段值
  • 不同类型获取静态值函数如下
GetStatic<type>Field Routine Name Native Type
GetStaticObjectField() jobject
GetStaticBooleanField() jboolean
GetStaticByteField() jbyte
GetStaticCharField() jchar
GetStaticShortField() jshort
GetStaticIntField() jint
GetStaticLongField() jlong
GetStaticFloatField() jfloat
GetStaticDoubleField() jdouble
  • 示例
JNIEXPORT void JNICALL Java_com_study_jnilearn_AccessField_accessStaticField(JNIEnv *env, jclass cls)
{
    jclass clazz;
    jfieldID fid;
    jint num;

    // 1.获取ClassField类的Class引用
    clazz = (*env)->FindClass(env, "com/study/jnilearn/ClassField");
    if (clazz == NULL)
    { // 错误处理
        return;
    }

    // 2.获取ClassField类静态变量num的属性ID
    fid = (*env)->GetStaticFieldID(env, clazz, "num", "I");
    if (fid == NULL)
    {
        return;
    }

    // 3.获取静态变量num的值
    num = (*env)->GetStaticIntField(env, clazz, fid);
    printf("In C--->ClassField.num = %d\n", num);

    // 4.修改静态变量num的值
    (*env)->SetStaticIntField(env, clazz, fid, 80);

    // 删除属部引用
    (*env)->DeleteLocalRef(env, clazz);
}

4 数组

4.1 获取数组长度

  • jsize GetArrayLength(JNIEnv *env, jarray array); : 返回数组长度

4.2 基本类型数组

4.2.1 获取基本类型数组

  • 获取数组的元素有 2 种方法:
  • NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, jboolean *isCopy); :返回数组首地址
    1. env: the JNI interface pointer.
    2. array: a Java string object.
    3. isCopy: a pointer to a boolean.
  • void Get<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf); :获取基本类型数组区间
    1. env: the JNI interface pointer.
    2. array: a Java array.
    3. start: the starting index.
    4. len: the number of elements to be copied.
    5. buf: the destination buffer.
  • Get<PrimitiveType>ArrayElements 函数簇如下:
Get<PrimitiveType>ArrayElements Routines Array Type Native Type
GetBooleanArrayElements() jbooleanArray jboolean
GetByteArrayElements() jbyteArray jbyte
GetCharArrayElements() jcharArray jchar
GetShortArrayElements() jshortArray jshort
GetIntArrayElements() jintArray jint
GetLongArrayElements() jlongArray jlong
GetFloatArrayElements() jfloatArray jfloat
GetDoubleArrayElements() jdoubleArray jdouble
  • Get<PrimitiveType>ArrayRegion 函数簇如下:
Get<PrimitiveType>ArrayRegion Routine Array Type Native Type
GetBooleanArrayRegion() jbooleanArray jboolean
GetByteArrayRegion() jbyteArray jbyte
GetCharArrayRegion() jcharArray jchar
GetShortArrayRegion() jshortArray jhort
GetIntArrayRegion() jintArray jint
GetLongArrayRegion() jlongArray jlong
GetFloatArrayRegion() jfloatArray jloat
GetDoubleArrayRegion() jdoubleArray jdouble

4.2.2 释放基本类型数组

  • void Release<PrimitiveType>ArrayElements (JNIEnv *env, ArrayType array, NativeType *elems, jint mode); :释放数组
  • env: the JNI interface pointer.
  • array: a Java array object.
  • elems: a pointer to array elements.
  • mode: the release mode.
  • Release<PrimitiveType>ArrayElements函数簇如下:
Release<PrimitiveType>ArrayElements Routines Array Type Native Type
ReleaseBooleanArrayElements() jbooleanArray jboolean
ReleaseByteArrayElements() jbyteArray jbyte
ReleaseCharArrayElements() jcharArray jchar
ReleaseShortArrayElements() jshortArray jshort
ReleaseIntArrayElements() jintArray jint
ReleaseLongArrayElements() jlongArray jlong
ReleaseFloatArrayElements() jfloatArray jfloat
ReleaseDoubleArrayElements() jdoubleArray jdouble

4.2.3 设置基本类型数组元素值

主要有 2 种方法: 1. 直接使用 void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, const NativeType *buf); 函数簇 1. env : the JNI interface pointer. 2. array : a Java array. 3. start : the starting index. 4. len : the number of elements to be copied. 5. buf : the source buffer. 2. 先使用 Get<PrimitiveType>ArrayElements 得到数组指针,再使用 Set<PrimitiveType>ArrayRegion 函数簇,最后使用 Release<PrimitiveType>ArrayElements 释放

  • 示例
void JNICALL Java_com_test_vediochat_h264_H264Android_test(JNIEnv *env, jobject thiz, jintArray javaArray, jbyteArray array2)
{
    //方法一
    /*
       jint temp1 = 45,temp2 = 20;
       (*env)->SetIntArrayRegion(env,javaArray,1,1,&temp1);
       (*env)->SetIntArrayRegion(env,javaArray,2,1,&temp2);
    */

    //方法二:
    jint *tempSize = (jint *)(*env)->GetIntArrayElements(env, javaArray, 0);
    tempSize[2] = 65;
    tempSize[3] = 75;
    (*env)->SetIntArrayRegion(env, javaArray, 0, 3, tempSize);
    (*env)->ReleaseIntArrayElements(env, javaArray, tempSize, 0);
}
  • Set<PrimitiveType>ArrayRegion 函数簇如下 | Set<PrimitiveType>ArrayRegion Routine | Array Type | Native Type | | ------------------------------------- | ------------- | ----------- | | SetBooleanArrayRegion() | jbooleanArray | jboolean | | SetByteArrayRegion() | jbyteArray | jbyte | | SetCharArrayRegion() | jcharArray | jchar | | SetShortArrayRegion() | jshortArray | jshort | | SetIntArrayRegion() | jintArray | jint | | SetLongArrayRegion() | jlongArray | jlong | | SetFloatArrayRegion() | jfloatArray | jfloat | | SetDoubleArrayRegion() | jdoubleArray | jdouble |

4.3 对象数组

对象只能从数组中一个一个的访问,和基本类型返回数组首地址不同。

4.3.1 获取对象类型数组

  • jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index);:获取指定索引的对象

4.3.2 设置对象类型数组元素值

  • void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value):设置指定索引的对象
    1. env: the JNI interface pointer.
    2. array: a Java array.
    3. index: array index.
    4. value: the new value.