JNIメソッドから複数の戻り値を受け取りたい場合、ネイティブの構造体を直接Javaに受け渡すことはできないため、JNIでJavaオブジェクトを作成するか配列を使用して受け渡すことになります。
JNIでJavaオブジェクトを作成する方法は割と複雑でパフォーマンスを上げるためにキャッシュ処理をしたりしないといけないので面倒です。ベクトルや行列を扱う場合は配列を使うのが簡単なのでこの方法を紹介します。
次のようなJava APIを使って、ネイティブコードでJava配列に値を設定することを考える。
Java
package com.mycompany;
public class MyClass {
private static native void putElements(float[] arr);
}
各要素を操作するには次のようにします。Get***ArrayElements
でポインタを取得して値を取得・代入して最後にRelease***ArrayElements
でポインタを開放します。***
の部分はデータ型によって使い分けます。
JNI
JNIEXPORT void JNICALL
Java_com_mycompany_MyClass_putElements(JNIEnv * env, jclass clazz, jfloatArray arr) {
jfloat *body = env->GetFloatArrayElements(arr, 0);
body[0] = 1.23f;
body[1] = 4.56f;
body[2] = 7.89f;
env->ReleaseFloatArrayElements(arr, body, 0);
}
Javaから渡された配列に入っている値をループで参照したい場合は、次のようにします。
JNI
JNIEXPORT void JNICALL
Java_com_mycompany_MyClass_iterateElements(JNIEnv * env, jclass clazz, jfloatArray arr) {
jsize len = env->GetArrayLength(arr);
jfloat *elements = env->GetFloatArrayElements(arr, 0);
for (int i = 0; i < len; ++i) {
float f = elements[i]; // 取得
elements[i] = 3.1415f; // 設定
}
env->ReleaseFloatArrayElements(arr, elements, 0);
}