2009-07-06 2 views
27

JNI-Tutorials, zum Beispiel this eine, decken ziemlich gut, wie primitive Felder innerhalb eines Objekts zugreifen, sowie wie auf Arrays zugreifen, die als explizite Funktionsargumente (d. H. Als Unterklassen von jarray) bereitgestellt werden. Aber wie auf Java (primitive) Arrays zugreifen, die Felder sind innerhalb ein jobject? Zum Beispiel würde Ich mag auf dem Byte-Array des folgenden Java-Objekts betreiben:Wie kann mit JNI auf Arrays innerhalb eines Objekts zugegriffen werden?

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

Das Hauptprogramm so etwas wie dies sein könnte:

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

Die entsprechende C++ Seite wäre dann:

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

ich dachte GetByteArrayElements zu verwenden, aber es ein ArrayType als Argument will. Offensichtlich vermisse ich etwas. Gibt es einen Weg dazu?

Antwort

34

Ich hoffe, dass Sie ein wenig helfen (überprüfen Sie die JNI Struct reference out, auch):

// 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 ich hier mit einem Verfahren anstelle eines Feldes arbeiten (ich als ein Java-Getter cleaner Aufruf), aber Sie wahrscheinlich kann es für die Felder auch neu schreiben. Vergiss nicht zu veröffentlichen und wie im Kommentar wirst du wahrscheinlich immer noch die Länge bekommen müssen.

Edit: Rewrite Ihres Beispiels, um es für ein Feld zu bekommen. Ersetzen Sie CallObjectMethod grundsätzlich durch 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

Dank; es ist clever (und vielleicht sogar sauberer), Getter zu verwenden. Ich muss es auf diese Weise tun, es sei denn, jemand zeigt auf, wie man die Array-Felder in GetXXXField-ähnlicher Weise direkt erhält. –

+1

Ok Ich habe ein Beispiel für das Feld hinzugefügt (benutze im Prinzip nur GetObjectField anstelle von CallObjectMethod). Obwohl ich natürlich nicht garantieren kann, dass es aus der Box läuft, hoffe ich, dass Sie die allgemeine Idee bekommen können :) – Daff

+2

Richtig! Irgendwie rechnete ich damit, etwas einfacher zu finden und daher zögerte ich, zu Definitionen zurückzukehren ("Array ist ein Objekt") :-) Programmierpsychologie ... Danke nochmal! –

1

In gcc 6.3 erhalte ich eine Warnung sagen „Typ-punned Zeiger Dereferenzierung wird streng-Aliasing Regeln brechen“ von einer Linie wie folgt aus:

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

Aber da jdoubleArray selbst einen Zeiger auf Klasse _jdoubleArray, es gibt keine Notwendigkeit, die Adresse vor dem Gießen zu erhalten, und diese static_cast funktioniert ohne Warnungen:

Verwandte Themen