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

Joo*_*kka 32 java-native-interface

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

class JavaClass {
  ...
  int i;
  byte[] a;
}
Run Code Online (Sandbox Code Playgroud)

主程序可能是这样的:

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);
}
Run Code Online (Sandbox Code Playgroud)

相应的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???
}
Run Code Online (Sandbox Code Playgroud)

我正在考虑使用GetByteArrayElements它,但它想要一个ArrayType作为它的论点.显然我错过了一些东西.有办法吗?

Daf*_*aff 39

我希望这会对你有所帮助(也可以查看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); 
Run Code Online (Sandbox Code Playgroud)

好的,我使用方法而不是字段(我考虑调用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);
}
Run Code Online (Sandbox Code Playgroud)

  • 对!不知何故,我期待找到一个更简单的方法来做到这一点,所以我不愿意回到定义("数组是一个对象":-)编程心理学......再次感谢! (2认同)

小智 5

在 gcc 6.3 中,我从这样的一行中收到一条警告,说“取消引用类型双关指针将破坏严格别名规则”:

jdoubleArray arr = *reinterpret_cast<jdoubleArray*>(&mvdata);
Run Code Online (Sandbox Code Playgroud)

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

jdoubleArray arr = static_cast<jdoubleArray>(mvdata);
Run Code Online (Sandbox Code Playgroud)