2009-07-06 19 views
27

Samouczki JNI, na przykład this jeden, obejmują całkiem dobrze, jak uzyskać dostęp do prymitywnych pól w obiekcie, a także jak uzyskać dostęp do tablic, które są dostarczane jako jawne argumenty funkcji (tj. Jako podklasy jarray). Ale jak uzyskać dostęp do tablic Java (prymitywnych), które są polami w ramach an jobject? Na przykład, chciałbym pracować na tablicy bajtów następującego obiektu Java:Jak uzyskać dostęp do tablic wewnątrz obiektu za pomocą JNI?

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

Program główny może być coś takiego:

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

Odpowiedni C++ strona będzie wówczas:

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

Myślałam użyć GetByteArrayElements, ale chce się ArrayType jako argument. Oczywiście, że czegoś brakuje. Czy jest na to sposób?

Odpowiedz

34

Mam nadzieję, że będzie trochę pomóc (sprawdź JNI Struct reference też):

// 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 tu pracować ze sposobem zamiast pola (I rozważyć powołanie getter czystsze Java), ale prawdopodobnie można go przepisać również dla pól. Nie zapomnij wydać i tak jak w komentarzu prawdopodobnie będziesz potrzebował jeszcze czasu.

Edytuj: Przepisz swój przykład, aby otrzymać go dla pola. Zasadniczo zastąp CallObjectMethod przez 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

Dzięki; jest to sprytne (a może nawet czystsze) użycie getterów. Będę musiał to zrobić w ten sposób, chyba że ktoś wskaże, jak uzyskać bezpośrednio pola tablicy, w stylu GetXXXField. –

+1

OK Dodałem przykład dla pola (w zasadzie po prostu użyj GetObjectField zamiast CallObjectMethod). Choć oczywiście nie mogę zagwarantować, że zabraknie go w pudełku, mam nadzieję, że uzyskasz ogólny pomysł :) – Daff

+2

Dobrze! Jakoś oczekiwałem, że znajdę nieco prostszy sposób, aby to zrobić, więc nie chciałem wracać do definicji ("array is an object" :-) Programowanie psychologii ... Jeszcze raz dziękuję! –

1

W gcc 6.3 dostaję ostrzeżenie mówiąc „wyłuskania type-punned wskaźnik złamie zasady ścisłego-aliasingu” z taką linię:

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

Ale ponieważ jdoubleArray sama jest wskaźnik do klasy _jdoubleArray, nie ma potrzeby uzyskiwania adresu przed rzutowaniem, a static_cast działa bez ostrzeżeń:

jdoubleArray arr = static_cast<jdoubleArray>(mvdata); 
Powiązane problemy