Вопрос по – Как получить доступ к массивам внутри объекта с помощью JNI?

31

JNI учебники, напримерэт one, достаточно подробно рассказывает, как получить доступ к примитивным полям в объекте, а также как получить доступ к массивам, которые предоставляются в качестве явных аргументов функции (то есть в качестве подклассовjarray). Но как получить доступ к Java (примитивным) массивам, которые являются полями anjobject? Например, я хотел бы работать с байтовым массивом следующего объекта Java:

class JavaClass {
  ...
  int i;
  byte[] a;
}

Основная программа может выглядеть примерно так:

class Test {

  public static void main(String[] args) {
    JavaClass jc = new JavaClass();
    jc.a = new byte[100];
    ...
    process(jc);
  }

  public static native void process(JavaClass jc);
}

Соответствующая сторона C ++ будет:

JNIEXPORT void JNICALL Java_Test_process(JNIEnv * env, jclass c, jobject jc) {

  jclass jcClass = env->GetObjectClass(jc);
  jfieldID iId = env->GetFieldID(jcClass, "i", "I");

  // This way we can get and set the "i" field. Let's double it:
  jint i = env->GetIntField(jc, iId);
  env->SetIntField(jc, iId, i * 2);

  // The jfieldID of the "a" field (byte array) can be got like this:
  jfieldID aId = env->GetFieldID(jcClass, "a", "[B");

  // But how do we operate on the array???
}

Я думал использоватьGetByteArrayElements, но он хочетArrayType в качестве аргумента. Очевидно, я что-то упустил. Есть ли способ к этому?

Ваш Ответ

2   ответа
38

JNI Struct ссылка, тоже):

// Get the class
jclass mvclass = env->GetObjectClass( *cls );
// Get method ID for method getSomeDoubleArray that returns a double array
jmethodID mid = env->GetMethodID( mvclass, "getSomeDoubleArray", "()[D");
// Call the method, returns JObject (because Array is instance of Object)
jobject mvdata = env->CallObjectMethod( *base, mid);
// Cast it to a jdoublearray
jdoubleArray * arr = reinterpret_cast<jdoubleArray*>(&mvdata)
// Get the elements (you probably have to fetch the length of the array as well
double * data = env->GetDoubleArrayElements(*arr, NULL);
// Don't forget to release it 
env->ReleaseDoubleArrayElements(*arr, data, 0); 

Хорошо, здесь я работаю с методом вместо поля (я подумал о том, чтобы вызвать очиститель Java getter), но вы, вероятно, можете переписать его и для полей. Не забудьте отпустить, и, как в комментарии, вам, вероятно, все еще нужно будет узнать длину.

Редактировать: переписать ваш пример, чтобы получить его для поля. В основном замените CallObjectMethod на GetObjectField.

JNIEXPORT void JNICALL Java_Test_process(JNIEnv * env, jclass c, jobject jc) {

  jclass jcClass = env->GetObjectClass(jc);
  jfieldID iId = env->GetFieldID(jcClass, "i", "I");

  // This way we can get and set the "i" field. Let's double it:
  jint i = env->GetIntField(jc, iId);
  env->SetIntField(jc, iId, i * 2);

  // The jfieldID of the "a" field (byte array) can be got like this:
  jfieldID aId = env->GetFieldID(jcClass, "a", "[B");

  // Get the object field, returns JObject (because Array is instance of Object)
  jobject mvdata = env->GetObjectField (jc, aID);

  // Cast it to a jdoublearray
  jdoubleArray * arr = reinterpret_cast<jdoubleArray*>(&mvdata)

  // Get the elements (you probably have to fetch the length of the array as well  
  double * data = env->GetDoubleArrayElements(*arr, NULL);

  // Don't forget to release it 
  env->ReleaseDoubleArrayElements(*arr, data, 0);
}
Правильно! Каким-то образом я ожидал найти более простой способ сделать это, и поэтому мне не хотелось возвращаться к определениям («массив - это объект» :-) Психология программирования ... Еще раз спасибо! Joonas Pulakka
Спасибо; умнее (и, возможно, даже чище) использовать добытчики. Мне придется делать это таким образом, если кто-то не укажет, как напрямую получить поля массива, как в GetXXXField-стиле. Joonas Pulakka
зачем использовать reinterpret_cast вместо статического приведения?
Я также видел то же самое в других ответах. Зачемdouble * data? Почему бы и нетjdouble * data?
Хорошо, я добавил вам пример для поля (в основном просто используйте GetObjectField вместо CallObjectMethod). Хотя я, конечно, не могу гарантировать, что он выйдет из коробки, я надеюсь, что вы можете получить общее представление :)
3

В gcc 6.3 я получаю предупреждение о том, что разыменование указателя типа-наказанного нарушит правила строгого наложения имен & quot; из такой строки:

jdoubleArray arr = *reinterpret_cast<jdoubleArray*>(&mvdata);

Но поскольку jdoubleArray сам по себе является указателем на класс _jdoubleArray, нет необходимости получать адрес перед преобразованием, и этот static_cast работает без предупреждений:

jdoubleArray arr = static_cast<jdoubleArray>(mvdata);

Похожие вопросы