鑑於(爪哇):
public class InputData {
public long in_size;
public byte[] data;
}
public class OutData {
public long out_size;
public byte[] data;
}
然後C++:
struct InputData
{
uint64_t in_size;
uint8_t *data;
};
struct OutputData
{
uint64_t out_size;
uint8_t *data;
};
OutputData* inputsToOutput(InputData** inputs, int numInputs)
{
//Do whatever here to convert them..
return NULL;
}
//Convert a Java inputData to C++ inputData
InputData* JavaInToCppIn(JNIEnv* env, jobject inputData)
{
jclass cls = env->GetObjectClass(inputData);
jlong in_size = env->GetLongField(inputData, env->GetFieldID(cls, "in_size", "J"));
jarray arr = static_cast<jarray>(env->GetObjectField(inputData, env->GetFieldID(cls, "data", "[B")));
jsize arrSize = env->GetArrayLength(arr);
if (in_size != arrSize)
{
return NULL;
}
InputData* inData = new (std::nothrow) InputData();
if (inData)
{
inData->in_size = in_size;
inData->data = new (std::nothrow) uint8_t[arrSize];
if (inData->data)
{
void* ptr = env->GetPrimitiveArrayCritical(arr, NULL);
memcpy(inData->data, ptr, sizeof(uint8_t) * arrSize);
env->ReleasePrimitiveArrayCritical(arr, ptr, 0);
return inData;
}
delete inData;
}
return NULL;
}
//Convert a Java OutputData to C++ OutputData
OutputData* JavaOutToCppOut(JNIEnv* env, jobject outputData)
{
jclass cls = env->GetObjectClass(outputData);
jlong out_size = env->GetLongField(outputData, env->GetFieldID(cls, "out_size", "J"));
jarray arr = static_cast<jarray>(env->GetObjectField(outputData, env->GetFieldID(cls, "data", "[B")));
jsize arrSize = env->GetArrayLength(arr);
if (out_size != arrSize)
{
return NULL;
}
OutputData* outData = new (std::nothrow) OutputData();
if (outData)
{
outData->out_size = out_size;
outData->data = new (std::nothrow) uint8_t[arrSize];
if (outData->data)
{
void* ptr = env->GetPrimitiveArrayCritical(arr, NULL);
memcpy(outData->data, ptr, sizeof(uint8_t) * arrSize);
env->ReleasePrimitiveArrayCritical(arr, ptr, 0);
return outData;
}
delete outData;
}
return NULL;
}
//Convert a C++ InputData to Java InputData
jobject CppInToJavaIn(JNIEnv* env, InputData* inData)
{
jclass cls = env->FindClass("Lpackage/Name/InputData;");
jobject res = env->NewObject(cls, env->GetMethodID(cls, "<init>", "()V"));
env->SetLongField(res, env->GetFieldID(cls, "in_size", "J"), inData->in_size);
jbyte* ptr = reinterpret_cast<jbyte*>(inData->data);
jbyteArray arr = env->NewByteArray(inData->in_size);
env->SetByteArrayRegion(arr, 0, inData->in_size, ptr);
env->SetObjectField(res, env->GetFieldID(cls, "data", "[B"), arr);
return res;
}
//Convert a C++ OutputData to a Java OutputData
jobject CppOutToJavaOut(JNIEnv* env, OutputData* outData)
{
jclass cls = env->FindClass("Lpackage/Name/OutputData;");
jobject res = env->NewObject(cls, env->GetMethodID(cls, "<init>", "()V"));
env->SetLongField(res, env->GetFieldID(cls, "out_size", "J"), outData->out_size);
jbyte* ptr = reinterpret_cast<jbyte*>(outData->data);
jbyteArray arr = env->NewByteArray(outData->out_size);
env->SetByteArrayRegion(arr, 0, outData->out_size, ptr);
env->SetObjectField(res, env->GetFieldID(cls, "data", "[B"), arr);
return res;
}
//Get Inputs from an ArrayList, convert them to an OutputData.
JNIEXPORT jobject JNICALL JAVA_package_name_getOutData(JNIEnv *env, jclass clazz, jobject inputDatas)
{
jclass arrayListClass = env->FindClass("Ljava/util/ArrayList;");
int arrayListSize = env->CallIntMethod(inputDatas, env->GetMethodID(arrayListClass, "size", "()I"));
if (arrayListSize > 0)
{
//Array of C++ inputs from Java..
InputData** inputs = new (std::nothrow) InputData*[arrayListSize];
if (inputs)
{
for (int i = 0; i < arrayListSize; ++i)
{
jobject jinput = env->NewGlobalRef(env->CallObjectMethod(inputDatas, env->GetMethodID(arrayListClass, "get", "(I)Ljava/lang/Object;"), i));
inputs[i] = JavaInToCppIn(env, jinput);
env->DeleteGlobalRef(jinput);
}
//Conver the C++ inputs to a C++ output, and then convert that C++ output into a Java OutputData.
OutputData* out = inputsToOutput(inputs, arrayListSize);
jobject output = CppOutToJavaOut(env, out);
//Clean-Up.
for (int i = 0; i < arrayListSize; ++i)
{
if (inputs[i])
{
delete[] inputs[i]->data;
}
delete inputs[i];
}
delete[] inputs;
delete out;
return output;
}
}
return NULL;
}
注:我用C++的new
和delete
,而不是malloc
和free
,但我一直是作爲nothrow
這樣就可以‘檢查’如果分配成功,而不是它拋出異常。也請注意,我沒有使用std::unique_ptr
或std::vector
或任何構造函數/析構函數/ RAII的東西,因爲我不知道你對容器或任何東西的限制。
只能通過強制轉換才能將C++類實例映射到Java類實例,反之亦然。請記住,每次你感受到投射的衝動時,這個投射通常是錯誤的工具,它告訴編譯器你知道你在做什麼。如果你不知道,那麼你只是誤導編譯器。我建議你從更簡單的事情開始。一個返回int的函數。當它工作時,試着在函數返回一個字符串,比如「Hello,殘忍的JNI世界!」。 –
@ Cheersandhth.-Alf,所以我需要使用(* env) - > NewObject創建一個Java類實例,並將outData複製到它,對吧? – Tamarous
就像那樣,是的。但不是直接嘗試,而是先做一些簡單的工作。總是一個好主意,以及不可思議的巨大流行的原因,否則這是無用的「你好,世界!」。 –