Java-JNI对象构造和字符串转换

本文介绍了JNI对象的构造和字符串的转换。

对象构造

JNI中,C++有时需要引用Java中的对象,例如ArrayList,这里介绍如何构建ArrayList和调用ArrayList的方法。

JNIEXPORT jobject JNICALL Java_Main_search(JNIEnv *env, jobject obj, jstring str)
{
    init();
    search(jstring2String(env, str));
    jclass clazz = env->FindClass("java/util/ArrayList");
    jobject list = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
    for (int i = 0; i < results.size(); ++i)
    {
        jstring tmpStr = env->NewStringUTF(results[i].c_str());
        env->CallBooleanMethod(list, env->GetMethodID(clazz,"add","(Ljava/lang/Object;)Z"), tmpStr);
        }
    return list;
}

这里,注意调用方法时,需要进行签名匹配,参考Java-JNI方法中的签名用法

同时,注意调用不同类型返回值的方法时,调用的函数名也不同,例如:

Boolean:env->CallBooleanMethod
Void:env->CallVoidMethod
Object:env->CallObjectMethod

如果不注意,将导致异常:

JNI DETECTED ERROR IN APPLICATION: 
JNI CallBooleanMethodV called with pending exception 'java.lang.NoSuchMethodError' thrown ..

字符串转换

Java中的String对象转换成C++中的std::string。

string jstring2String(JNIEnv *env, jstring jstr)
{
    char *bytes= NULL;
    jclass classString = env->FindClass("java/lang/String");
    jbyteArray byteArray = (jbyteArray)env->CallObjectMethod(jstr, env->GetMethodID(classString, "getBytes", "(Ljava/lang/String;)[B"), env->NewStringUTF("UTF8"));
    jsize length = env->GetArrayLength(byteArray);
    jbyte *jbytes = env->GetByteArrayElements(byteArray, JNI_FALSE);
    if(length > 0){
        bytes = (char*)malloc(length + 1);
        memcpy(bytes, jbytes, length);
        bytes[length] = 0;
    }
    env->ReleaseByteArrayElements(byteArray, jbytes, 0);
    string s(bytes);
    free(bytes);
    return s;
}

注意,C++的byte数组最后一个字符是’\0’,所以比Java的String长度多一位。