如何使用 JNI 访问对象内的数组? [英] How to access arrays within an object with JNI?

查看:21
本文介绍了如何使用 JNI 访问对象内的数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JNI tutorials, for instance this one, cover quite well how to access primitive fields within an object, as well as how to access arrays that are provided as explicit function arguments (i.e. as subclasses of jarray). But how to access Java (primitive) arrays that are fields within an jobject? For instance, I'd like to operate on the byte array of the following Java object:

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

The main program could be something like this:

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);
}

The corresponding C++ side would then be:

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???
}

I was thinking to use GetByteArrayElements, but it wants an ArrayType as its argument. Obviously I'm missing something. Is there a way to to this?

解决方案

I hope that will help you a little (check out the JNI Struct reference, too):

// 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); 

Ok here I operate with a method instead of a field (I considered calling a Java getter cleaner) but you probably can rewrite it for the fields as well. Don't forget to release and as in the comment you'll probably still need to get the length.

Edit: Rewrite of your example to get it for a field. Basically replace CallObjectMethod by 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);
}

这篇关于如何使用 JNI 访问对象内的数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆