本文介绍了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长度多一位。