JNIEXPORT jobjectArray JNICALL Java_class_method(JNIEnv * env,jobject o,jbyteArray dataToSegment);
在Java方面,它很简单:
byte[] arg = getRandomByteArray(); Object[] retVal = x.method(arg);
现在,我发现JNI部分有点棘手.我打算创建一个对象数组,每个对象都是一个字节数组.这是因为JNI仅定义了有限数量的Java类型.有一个jbyteArray类型和一个jobjectArray类型,但没有jarrayOfByteArrays类型.
所以我创建了我的对象数组,每个对象被初始化为一个新的字节[1024]:
jobjectArray retVal = env->NewObjectArray(numSegs,env->FindClass("[Ljava/lang/Object;"),env->NewByteArray(1024));
然后我遍历这个数组中的所有索引,执行如下操作:
jbyteArray tmp = (jbyteArray) env->GetObjectArrayElement(retVal,i); env->SetByteArrayRegion(tmp,size,(jbyte*) sourceBuffer); env->SetObjectArrayElement(retVal,i,(jobject) tmp); // <--- Questionable line
在大多数情况下,一切都很好.但是,如果我希望每个字节数组都是可变长度怎么办?也就是说,我希望字节数组的数组“锯齿状”.作为初始值,我作为NewObjectArray()的最后一个参数传递什么?我尝试传递0作为初始值以防止在创建jobjectArray时初始化,然后分配新的jbyteArray对象以传递给SetObjectArrayElement(),但这只会在每次我尝试调用SetObjectArrayElement时抛出ArrayStoreException.实际上,即使为tmp对象(而不是GetObjectArrayElement()中的一个)分配新的jbyteArray,也会导致在调用SetObjectArrayElement()时抛出相同的异常.有没有理由说最后一行代码会成为问题?是否无法使用jbyteArray作为参数调用SetObjectArrayElement()?
经过进一步检查,似乎“可疑线”根本没有做任何事情.当我评论它时,对tmp所做的任何更改都会反映在retVal中.我理解这是因为SetByteArrayRegion调用正在处理jobjectArray中的“in”字节数组,而不是副本.如果所有行(相反,所有单维字节数组)的长度相同,那对我来说就足够了.但他们不是.如何将新字节数组分配给此对象数组中的一行?
TL; DR:
使用JNI,我有一个jobjectArray的jbyteArrays.如何用一个用NewByteArray创建的新jbyteArray替换其中一个jbyteArrays?提示:env-> SetObjectArrayElement(retVal,(jobject)env-> NewByteArray(size)); //不起作用
解决方法
static jbyteArray NewJavaStringBytes(JNIEnv* env,const char *src) { jbyteArray retVal = (*env)->NewByteArray(env,strlen(src)); jbyte *buf = (*env)->GetByteArrayElements(env,retVal,NULL); strcpy(buf,src); printf(" NewJavaStringBytes: Created java byte array: %s.\n",buf); (*env)->ReleaseByteArrayElements(env,buf,0); return retVal; } JNIEXPORT jobjectArray JNICALL Java_TestJniString_printStringArray (JNIEnv *env,jobject thisObj,jobjectArray jObjArr) { int numStr = (*env)->GetArrayLength(env,jObjArr); int idx = 0; jobjectArray strArr = NULL; jbyte *curStr = NULL; jclass arrayElemType = (*env)->FindClass(env,"[B"); const char *retStrs[] = {"one","two","three","twenty-five","TESTING!!"}; const int RET_LEN = sizeof(retStrs) / sizeof(char *); printf("Creating java object array of %d items.\n",RET_LEN); //Create new array of byte array jobjectArray testArray = (*env)->NewObjectArray(env,RET_LEN,arrayElemType,(*env)->NewByteArray(env,1) ); for (idx = 0; idx < RET_LEN; ++idx) { printf("Creating java byte array %d from str: %s.\n",idx,retStrs[idx]); jbyteArray str = NewJavaStringBytes(env,retStrs[idx]); (*env)->SetObjectArrayElement(env,testArray,str); (*env)->DeleteLocalRef(env,str); } printf("printStringArray: Printing %d strings:\n",numStr); for (idx = 0; idx < numStr; ++idx) { strArr = (*env)->GetObjectArrayElement(env,jObjArr,idx); curStr = (*env)->GetByteArrayElements(env,strArr,NULL); printf(" %s.\n",curStr); (*env)->ReleaseByteArrayElements(env,(jbyteArray)strArr,curStr,0); } (*env)->DeleteGlobalRef(env,arrayElemType); return testArray; }
此示例采用字节数组数组并返回字节数组数组.注意这是在C(而不是C)中所以jni调用是(* env) – >(env,…);.在C中,包装器简化了调用.另外,请注意,这假定java代码在发送到本机层之前在字符串的字节数组版本上添加空终止符.如果您不能指望它,则必须在C/C++代码中手动添加空术语,因为从String转换时Java不会对byte []执行此操作.
希望有所帮助.