2009-07-06 17 views
27

JNI tutoriales, por ejemplo this, cubre bastante bien cómo acceder a campos primitivos dentro de un objeto, así como también cómo acceder a matrices que se proporcionan como argumentos explícitos de funciones (es decir, como subclases de jarray). Pero, ¿cómo acceder a las matrices Java (primitivas) que son campos dentro de y jobject? Por ejemplo, me gustaría operar en la matriz de bytes de los siguientes objetos de Java:¿Cómo acceder a las matrices dentro de un objeto con JNI?

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

El programa principal podría ser algo como esto:

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

El correspondiente C++ lado sería entonces:

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

estaba pensando usar GetByteArrayElements, pero quiere una ArrayType como su argumento. Obviamente me falta algo. ¿Hay alguna forma de hacerlo?

Respuesta

34

espero que le ayudará un poco (echa un vistazo a la JNI Struct reference, también):

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

autorización aquí que operan con un método en lugar de un campo (I en llamar a un limpiador captador de Java) pero probablemente también pueda reescribirlo para los campos. No te olvides de soltar y, como en el comentario, es probable que aún necesites obtener la longitud.

Editar: reescriba su ejemplo para obtener un campo. Básicamente reemplazar CallObjectMethod por 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); 
} 
+0

Gracias; es inteligente (y tal vez incluso más limpio) usar getters. Tendré que hacerlo de esta manera a menos que alguien señale cómo obtener directamente los campos de la matriz, en forma de GetXXXField. –

+1

Ok, le agregué un ejemplo para el campo (básicamente solo uso GetObjectField en lugar de CallObjectMethod). Aunque, por supuesto, no puedo garantizar que se ejecutará de la caja espero que pueda obtener la idea general :) – Daff

+2

¡Correcto! De alguna manera, esperaba encontrar una forma un poco más directa de hacerlo, y por eso me resistí a volver a las definiciones ("array es un objeto" :-) Programación de la psicología ... ¡Gracias de nuevo! –

1

En gcc 6.3 me sale un aviso que dice "dereferencing puntero del tipo hizo juegos de palabras va a romper las reglas estrictas-aliasing" de una línea como esta:

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

Pero desde jdoubleArray es en sí mismo un puntero a la clase _jdoubleArray, no es necesario obtener la dirección antes del lanzamiento, y este static_cast funciona sin advertencias:

jdoubleArray arr = static_cast<jdoubleArray>(mvdata); 
Cuestiones relacionadas