如何使用JNI访问对象中的数组?

时间:2009-07-06 11:53:36

标签: java-native-interface

JNI教程,例如this一,很好地介绍了如何访问对象中的原始字段,以及如何访问作为显式函数参数提供的数组(即作为{{1}的子类})。但是如何访问 jarray字段的Java(原始)数组?例如,我想操作以下Java对象的字节数组:

jobject

主程序可能是这样的:

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

相应的C ++方面将是:

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

我正在考虑使用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作为其参数。显然我错过了一些东西。有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:38)

我希望这会对你有所帮助(也可以查看JNI Struct reference):

// 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清理器),但你可能也可以为字段重写它。不要忘记发布,并且在评论中你可能仍需要获得长度。

编辑:重写您的示例以获取字段。基本上用GetObjectField替换CallObjectMethod。

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

答案 1 :(得分:3)

在gcc 6.3中,我得到一个警告说&#34;解除引用类型惩罚指针会破坏严格别名规则&#34;从这样的一行:

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

但是由于jdoubleArray本身是一个指向类_jdoubleArray的指针,因此在转换之前不需要获取地址,并且此static_cast在没有警告的情况下工作:

jdoubleArray arr = static_cast<jdoubleArray>(mvdata);